/*
 * Copyright 2020 HIMSA II K/S - www.himsa.com.
 * Represented by EHIMA - www.ehima.com
 *
 * 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 <gmock/gmock.h>
#include <gtest/gtest.h>

#include "btm_iso_api.h"
#include "hci/controller_interface_mock.h"
#include "hci/hci_packets.h"
#include "hci/include/hci_layer.h"
#include "mock_hcic_layer.h"
#include "osi/include/allocator.h"
#include "stack/btm/btm_dev.h"
#include "stack/include/bt_hdr.h"
#include "stack/include/bt_types.h"
#include "stack/include/hci_error_code.h"
#include "stack/include/hcidefs.h"
#include "test/mock/mock_main_shim_entry.h"
#include "test/mock/mock_main_shim_hci_layer.h"

// TODO(b/369381361) Enfore -Wmissing-prototypes
#pragma GCC diagnostic ignored "-Wmissing-prototypes"

using bluetooth::hci::IsoManager;
using testing::_;
using testing::AnyNumber;
using testing::AtLeast;
using testing::Eq;
using testing::Matcher;
using testing::Return;
using testing::SaveArg;
using testing::StrictMock;
using testing::Test;

// for function pointer testing purpose
bool IsIsoActive = false;

tBTM_SEC_DEV_REC* btm_find_dev_by_handle(uint16_t /* handle */) { return nullptr; }
void BTM_LogHistory(const std::string& /* tag */, const RawAddress& /* bd_addr */,
                    const std::string& /* msg */, const std::string& /* extra */) {}

namespace bluetooth::shim {
class IsoInterface {
public:
  virtual void HciSend(BT_HDR* packet) = 0;
  virtual ~IsoInterface() = default;
};

class MockIsoInterface : public IsoInterface {
public:
  MOCK_METHOD((void), HciSend, (BT_HDR * p_msg), (override));
};

static MockIsoInterface* iso_interface = nullptr;
static void SetMockIsoInterface(MockIsoInterface* interface) { iso_interface = interface; }

static void set_data_cb(base::Callback<void(BT_HDR*)> /* send_data_cb */) {
  FAIL() << __func__ << " should never be called";
}

static void transmit_command(const BT_HDR* /* command */,
                             command_complete_cb /* complete_callback */,
                             command_status_cb /* status_cb */, void* /* context */) {
  FAIL() << __func__ << " should never be called";
}

static void transmit_downward(void* data, uint16_t /* iso_Data_size */) {
  iso_interface->HciSend((BT_HDR*)data);
  osi_free(data);
}

static hci_t interface = {.set_data_cb = set_data_cb,
                          .transmit_command = transmit_command,
                          .transmit_downward = transmit_downward};

}  // namespace bluetooth::shim

namespace {
class MockCigCallbacks : public bluetooth::hci::iso_manager::CigCallbacks {
public:
  MockCigCallbacks() = default;
  MockCigCallbacks(const MockCigCallbacks&) = delete;
  MockCigCallbacks& operator=(const MockCigCallbacks&) = delete;

  ~MockCigCallbacks() override = default;

  MOCK_METHOD((void), OnSetupIsoDataPath, (uint8_t status, uint16_t conn_handle, uint8_t cig_id),
              (override));
  MOCK_METHOD((void), OnRemoveIsoDataPath, (uint8_t status, uint16_t conn_handle, uint8_t cig_id),
              (override));
  MOCK_METHOD((void), OnIsoLinkQualityRead,
              (uint8_t conn_handle, uint8_t cig_id, uint32_t txUnackedPackets,
               uint32_t txFlushedPackets, uint32_t txLastSubeventPackets,
               uint32_t retransmittedPackets, uint32_t crcErrorPackets,
               uint32_t rxUnreceivedPackets, uint32_t duplicatePackets),
              (override));

  MOCK_METHOD((void), OnCisEvent, (uint8_t event, void* data), (override));
  MOCK_METHOD((void), OnCigEvent, (uint8_t event, void* data), (override));
};

class MockBigCallbacks : public bluetooth::hci::iso_manager::BigCallbacks {
public:
  MockBigCallbacks() = default;
  MockBigCallbacks(const MockBigCallbacks&) = delete;
  MockBigCallbacks& operator=(const MockBigCallbacks&) = delete;

  ~MockBigCallbacks() override = default;

  MOCK_METHOD((void), OnSetupIsoDataPath, (uint8_t status, uint16_t conn_handle, uint8_t big_id),
              (override));
  MOCK_METHOD((void), OnRemoveIsoDataPath, (uint8_t status, uint16_t conn_handle, uint8_t big_id),
              (override));

  MOCK_METHOD((void), OnBigEvent, (uint8_t event, void* data), (override));
};
}  // namespace

class IsoManagerTest : public Test {
protected:
  void SetUp() override {
    bluetooth::shim::SetMockIsoInterface(&iso_interface_);
    hcic::SetMockHcicInterface(&hcic_interface_);
    bluetooth::shim::testing::hci_layer_set_interface(&bluetooth::shim::interface);
    bluetooth::hci::testing::mock_controller_ = &controller_;

    big_callbacks_.reset(new MockBigCallbacks());
    cig_callbacks_.reset(new MockCigCallbacks());
    IsIsoActive = false;

    iso_sizes_.total_num_le_packets_ = 6;
    iso_sizes_.le_data_packet_length_ = 1024;
    ON_CALL(controller_, GetControllerIsoBufferSize()).WillByDefault(Return(iso_sizes_));

    InitIsoManager();
  }

  void TearDown() override {
    CleanupIsoManager();

    big_callbacks_.reset();
    cig_callbacks_.reset();

    bluetooth::shim::SetMockIsoInterface(nullptr);
    hcic::SetMockHcicInterface(nullptr);
    bluetooth::shim::testing::hci_layer_set_interface(nullptr);
    bluetooth::hci::testing::mock_controller_ = nullptr;
  }

  virtual void InitIsoManager() {
    manager_instance_ = IsoManager::GetInstance();
    manager_instance_->Start();
    manager_instance_->RegisterCigCallbacks(cig_callbacks_.get());
    manager_instance_->RegisterBigCallbacks(big_callbacks_.get());
    manager_instance_->RegisterOnIsoTrafficActiveCallback(iso_active_callback);

    // Default mock SetCigParams action
    volatile_test_cig_create_cmpl_evt_ = kDefaultCigParamsEvt;
    ON_CALL(hcic_interface_, SetCigParams)
            .WillByDefault([this](auto cig_id, auto,
                                  base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
              uint8_t hci_mock_rsp_buffer[3 + sizeof(uint16_t) *
                                                      this->volatile_test_cig_create_cmpl_evt_
                                                              .conn_handles.size()];
              uint8_t* p = hci_mock_rsp_buffer;

              UINT8_TO_STREAM(p, this->volatile_test_cig_create_cmpl_evt_.status);
              UINT8_TO_STREAM(p, cig_id);
              UINT8_TO_STREAM(p, this->volatile_test_cig_create_cmpl_evt_.conn_handles.size());
              for (auto handle : this->volatile_test_cig_create_cmpl_evt_.conn_handles) {
                UINT16_TO_STREAM(p, handle);
              }

              std::move(cb).Run(
                      hci_mock_rsp_buffer,
                      3 + sizeof(uint16_t) *
                                      this->volatile_test_cig_create_cmpl_evt_.conn_handles.size());
              return 0;
            });

    // Default mock CreateCis action
    ON_CALL(hcic_interface_, CreateCis)
            .WillByDefault([](uint8_t num_cis, const EXT_CIS_CREATE_CFG* cis_cfg,
                              base::OnceCallback<void(uint8_t*, uint16_t)> /* cb */) {
              for (const EXT_CIS_CREATE_CFG* cis = cis_cfg; num_cis != 0; num_cis--, cis++) {
                std::vector<uint8_t> buf(28);
                uint8_t* p = buf.data();
                UINT8_TO_STREAM(p, HCI_SUCCESS);
                UINT16_TO_STREAM(p, cis->cis_conn_handle);
                UINT24_TO_STREAM(p, 0xEA);    // CIG sync delay
                UINT24_TO_STREAM(p, 0xEB);    // CIS sync delay
                UINT24_TO_STREAM(p, 0xEC);    // transport latency mtos
                UINT24_TO_STREAM(p, 0xED);    // transport latency stom
                UINT8_TO_STREAM(p, 0x01);     // phy mtos
                UINT8_TO_STREAM(p, 0x02);     // phy stom
                UINT8_TO_STREAM(p, 0x01);     // nse
                UINT8_TO_STREAM(p, 0x02);     // bn mtos
                UINT8_TO_STREAM(p, 0x03);     // bn stom
                UINT8_TO_STREAM(p, 0x04);     // ft mtos
                UINT8_TO_STREAM(p, 0x05);     // ft stom
                UINT16_TO_STREAM(p, 0x00FA);  // Max PDU mtos
                UINT16_TO_STREAM(p, 0x00FB);  // Max PDU stom
                UINT16_TO_STREAM(p, 0x0C60);  // ISO interval

                IsoManager::GetInstance()->HandleHciEvent(HCI_BLE_CIS_EST_EVT, buf.data(),
                                                          buf.size());
              }
            });

    // Default mock disconnect action
    ON_CALL(hcic_interface_, Disconnect).WillByDefault([](uint16_t handle, uint8_t reason) {
      IsoManager::GetInstance()->HandleDisconnect(handle, reason);
    });

    // Default mock CreateBig HCI action
    volatile_test_big_params_evt_ = kDefaultBigParamsEvt;
    ON_CALL(hcic_interface_, CreateBig)
            .WillByDefault([this](auto big_handle,
                                  bluetooth::hci::iso_manager::big_create_params big_params) {
              std::vector<uint8_t> buf(big_params.num_bis * sizeof(uint16_t) + 18);
              uint8_t* p = buf.data();
              UINT8_TO_STREAM(p, HCI_SUCCESS);
              UINT8_TO_STREAM(p, big_handle);

              ASSERT_TRUE(big_params.num_bis <= volatile_test_big_params_evt_.conn_handles.size());

              UINT24_TO_STREAM(p, volatile_test_big_params_evt_.big_sync_delay);
              UINT24_TO_STREAM(p, volatile_test_big_params_evt_.transport_latency_big);
              UINT8_TO_STREAM(p, big_params.phy);
              UINT8_TO_STREAM(p, volatile_test_big_params_evt_.nse);
              UINT8_TO_STREAM(p, volatile_test_big_params_evt_.bn);
              UINT8_TO_STREAM(p, volatile_test_big_params_evt_.pto);
              UINT8_TO_STREAM(p, volatile_test_big_params_evt_.irc);
              UINT16_TO_STREAM(p, volatile_test_big_params_evt_.max_pdu);
              UINT16_TO_STREAM(p, volatile_test_big_params_evt_.iso_interval);

              UINT8_TO_STREAM(p, big_params.num_bis);
              for (auto i = 0; i < big_params.num_bis; ++i) {
                UINT16_TO_STREAM(p, volatile_test_big_params_evt_.conn_handles[i]);
              }

              IsoManager::GetInstance()->HandleHciEvent(HCI_BLE_CREATE_BIG_CPL_EVT, buf.data(),
                                                        buf.size());
            });

    // Default mock TerminateBig HCI action
    ON_CALL(hcic_interface_, TerminateBig).WillByDefault([](auto big_handle, uint8_t reason) {
      std::vector<uint8_t> buf(2);
      uint8_t* p = buf.data();
      UINT8_TO_STREAM(p, big_handle);
      UINT8_TO_STREAM(p, reason);

      IsoManager::GetInstance()->HandleHciEvent(HCI_BLE_TERM_BIG_CPL_EVT, buf.data(), buf.size());
    });

    // Default mock SetupIsoDataPath HCI action
    ON_CALL(hcic_interface_, SetupIsoDataPath)
            .WillByDefault([](uint16_t iso_handle, uint8_t /* data_path_dir */,
                              uint8_t /* data_path_id */, uint8_t /* codec_id_format */,
                              uint16_t /* codec_id_company */, uint16_t /* codec_id_vendor */,
                              uint32_t /* controller_delay */,
                              std::vector<uint8_t> /* codec_conf */,
                              base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
              std::vector<uint8_t> buf(3);
              uint8_t* p = buf.data();
              UINT8_TO_STREAM(p, HCI_SUCCESS);
              UINT16_TO_STREAM(p, iso_handle);

              std::move(cb).Run(buf.data(), buf.size());
            });

    // Default mock RemoveIsoDataPath HCI action
    ON_CALL(hcic_interface_, RemoveIsoDataPath)
            .WillByDefault([](uint16_t iso_handle, uint8_t /* data_path_dir */,
                              base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
              std::vector<uint8_t> buf(3);
              uint8_t* p = buf.data();
              UINT8_TO_STREAM(p, HCI_SUCCESS);
              UINT16_TO_STREAM(p, iso_handle);

              std::move(cb).Run(buf.data(), buf.size());
            });
  }

  virtual void CleanupIsoManager() {
    manager_instance_->Stop();
    manager_instance_ = nullptr;
  }

  static const bluetooth::hci::iso_manager::big_create_params kDefaultBigParams;
  static const bluetooth::hci::iso_manager::cig_create_params kDefaultCigParams;
  static const bluetooth::hci::iso_manager::cig_create_params kDefaultCigParams2;
  static const bluetooth::hci::iso_manager::cig_create_cmpl_evt kDefaultCigParamsEvt;
  static const bluetooth::hci::iso_manager::big_create_cmpl_evt kDefaultBigParamsEvt;
  static const bluetooth::hci::iso_manager::iso_data_path_params kDefaultIsoDataPathParams;

  bluetooth::hci::iso_manager::cig_create_cmpl_evt volatile_test_cig_create_cmpl_evt_;
  bluetooth::hci::iso_manager::big_create_cmpl_evt volatile_test_big_params_evt_;

  IsoManager* manager_instance_;
  bluetooth::shim::MockIsoInterface iso_interface_;
  hcic::MockHcicInterface hcic_interface_;
  bluetooth::hci::testing::MockControllerInterface controller_;
  bluetooth::hci::LeBufferSize iso_sizes_;

  std::unique_ptr<MockBigCallbacks> big_callbacks_;
  std::unique_ptr<MockCigCallbacks> cig_callbacks_;
  void (*iso_active_callback)(bool) = [](bool active) { IsIsoActive = active; };
};

const bluetooth::hci::iso_manager::cig_create_cmpl_evt IsoManagerTest::kDefaultCigParamsEvt = {
        .status = 0x00,
        .cig_id = 128,
        .conn_handles = std::vector<uint16_t>({0x0EFF, 0x00FF}),
};

const bluetooth::hci::iso_manager::big_create_cmpl_evt IsoManagerTest::kDefaultBigParamsEvt = {
        .status = 0x00,
        .big_id = 0,
        .big_sync_delay = 0x0080de,
        .transport_latency_big = 0x00cefe,
        .phy = 0x02,
        .nse = 4,
        .bn = 1,
        .pto = 0,
        .irc = 4,
        .max_pdu = 108,
        .iso_interval = 6,
        .conn_handles = std::vector<uint16_t>({0x0EFE, 0x0E00}),
};

const bluetooth::hci::iso_manager::iso_data_path_params IsoManagerTest::kDefaultIsoDataPathParams =
        {
                .data_path_dir = bluetooth::hci::iso_manager::kIsoDataPathDirectionOut,
                .data_path_id = bluetooth::hci::iso_manager::kIsoDataPathHci,
                .codec_id_format = 0x06,
                .codec_id_company = 0,
                .codec_id_vendor = 0,
                .controller_delay = 0,
                .codec_conf = {0x02, 0x01, 0x02},
};

const bluetooth::hci::iso_manager::big_create_params IsoManagerTest::kDefaultBigParams = {
        .adv_handle = 0x00,
        .num_bis = 2,
        .sdu_itv = 0x002710,
        .max_sdu_size = 108,
        .max_transport_latency = 0x3c,
        .rtn = 3,
        .phy = 0x02,
        .packing = 0x00,
        .framing = 0x00,
        .enc = 0,
        .enc_code = std::array<uint8_t, 16>({0}),
};

const bluetooth::hci::iso_manager::cig_create_params IsoManagerTest::kDefaultCigParams = {
        .sdu_itv_mtos = 0x00002710,
        .sdu_itv_stom = 0x00002711,
        .sca = bluetooth::hci::iso_manager::kIsoSca0To20Ppm,
        .packing = 0x00,
        .framing = 0x01,
        .max_trans_lat_stom = 0x000A,
        .max_trans_lat_mtos = 0x0009,
        .cis_cfgs =
                {
                        // CIS #1
                        {
                                .cis_id = 1,
                                .max_sdu_size_mtos = 0x0028,
                                .max_sdu_size_stom = 0x0027,
                                .phy_mtos = 0x04,
                                .phy_stom = 0x03,
                                .rtn_mtos = 0x02,
                                .rtn_stom = 0x01,
                        },
                        // CIS #2
                        {
                                .cis_id = 2,
                                .max_sdu_size_mtos = 0x0029,
                                .max_sdu_size_stom = 0x002A,
                                .phy_mtos = 0x09,
                                .phy_stom = 0x08,
                                .rtn_mtos = 0x07,
                                .rtn_stom = 0x06,
                        },
                },
};

const bluetooth::hci::iso_manager::cig_create_params IsoManagerTest::kDefaultCigParams2 = {
        .sdu_itv_mtos = 0x00002709,
        .sdu_itv_stom = 0x00002700,
        .sca = bluetooth::hci::iso_manager::kIsoSca0To20Ppm,
        .packing = 0x01,
        .framing = 0x00,
        .max_trans_lat_stom = 0x000B,
        .max_trans_lat_mtos = 0x0006,
        .cis_cfgs =
                {
                        // CIS #1
                        {
                                .cis_id = 1,
                                .max_sdu_size_mtos = 0x0022,
                                .max_sdu_size_stom = 0x0022,
                                .phy_mtos = 0x01,
                                .phy_stom = 0x02,
                                .rtn_mtos = 0x02,
                                .rtn_stom = 0x01,
                        },
                        // CIS #2
                        {
                                .cis_id = 2,
                                .max_sdu_size_mtos = 0x002A,
                                .max_sdu_size_stom = 0x002B,
                                .phy_mtos = 0x06,
                                .phy_stom = 0x06,
                                .rtn_mtos = 0x07,
                                .rtn_stom = 0x07,
                        },
                },
};

class IsoManagerDeathTest : public IsoManagerTest {};

class IsoManagerDeathTestNoInit : public IsoManagerTest {
protected:
  void InitIsoManager() override { /* DO NOTHING */ }

  void CleanupIsoManager() override { /* DO NOTHING */ }
};

class IsoManagerDeathTestNoCleanup : public IsoManagerTest {
protected:
  void CleanupIsoManager() override { /* DO NOTHING */ }
};

bool operator==(const EXT_CIS_CFG& x, const EXT_CIS_CFG& y) {
  return (x.cis_id == y.cis_id) && (x.max_sdu_size_mtos == y.max_sdu_size_mtos) &&
         (x.max_sdu_size_stom == y.max_sdu_size_stom) && (x.phy_mtos == y.phy_mtos) &&
         (x.phy_stom == y.phy_stom) && (x.rtn_mtos == y.rtn_mtos) && (x.rtn_stom == y.rtn_stom);
}

bool operator==(const struct bluetooth::hci::iso_manager::cig_create_params& x,
                const struct bluetooth::hci::iso_manager::cig_create_params& y) {
  return (x.sdu_itv_mtos == y.sdu_itv_mtos) && (x.sdu_itv_stom == y.sdu_itv_stom) &&
         (x.sca == y.sca) && (x.packing == y.packing) && (x.framing == y.framing) &&
         (x.max_trans_lat_stom == y.max_trans_lat_stom) &&
         (x.max_trans_lat_mtos == y.max_trans_lat_mtos) &&
         std::is_permutation(x.cis_cfgs.begin(), x.cis_cfgs.end(), y.cis_cfgs.begin());
}

bool operator==(const struct bluetooth::hci::iso_manager::big_create_params& x,
                const struct bluetooth::hci::iso_manager::big_create_params& y) {
  return (x.adv_handle == y.adv_handle) && (x.num_bis == y.num_bis) && (x.sdu_itv == y.sdu_itv) &&
         (x.max_sdu_size == y.max_sdu_size) &&
         (x.max_transport_latency == y.max_transport_latency) && (x.rtn == y.rtn) &&
         (x.phy == y.phy) && (x.packing == y.packing) && (x.framing == y.framing) &&
         (x.enc == y.enc) && (x.enc_code == y.enc_code);
}

namespace iso_matchers {
MATCHER_P(Eq, value, "") { return arg == value; }
MATCHER_P2(EqPointedArray, value, len, "") { return !std::memcmp(arg, value, len); }
}  // namespace iso_matchers

TEST_F(IsoManagerTest, SingletonAccess) {
  auto* iso_mgr = IsoManager::GetInstance();
  ASSERT_EQ(manager_instance_, iso_mgr);
}

TEST_F(IsoManagerTest, RegisterCallbacks) {
  auto* iso_mgr = IsoManager::GetInstance();
  ASSERT_EQ(manager_instance_, iso_mgr);

  iso_mgr->RegisterBigCallbacks(big_callbacks_.get());
  iso_mgr->RegisterCigCallbacks(cig_callbacks_.get());
  iso_mgr->RegisterOnIsoTrafficActiveCallback(iso_active_callback);
}

TEST_F(IsoManagerDeathTestNoInit, RegisterNullBigCallbacks) {
  IsoManager::GetInstance()->Start();

  ASSERT_EXIT(IsoManager::GetInstance()->RegisterBigCallbacks(nullptr),
              ::testing::KilledBySignal(SIGABRT), "Invalid BIG callbacks");

  // Manual cleanup as IsoManagerDeathTest has no 'generic' cleanup
  IsoManager::GetInstance()->Stop();
}

TEST_F(IsoManagerDeathTestNoInit, RegisterNullCigCallbacks) {
  IsoManager::GetInstance()->Start();

  ASSERT_EXIT(IsoManager::GetInstance()->RegisterCigCallbacks(nullptr),
              ::testing::KilledBySignal(SIGABRT), "Invalid CIG callbacks");

  // Manual cleanup as IsoManagerDeathTest has no 'generic' cleanup
  IsoManager::GetInstance()->Stop();
}

// Verify hci layer being called by the Iso Manager
TEST_F(IsoManagerTest, CreateCigHciCall) {
  for (uint8_t i = 220; i != 60; ++i) {
    EXPECT_CALL(hcic_interface_, SetCigParams(i, iso_matchers::Eq(kDefaultCigParams), _))
            .Times(1)
            .RetiresOnSaturation();
    IsoManager::GetInstance()->CreateCig(i, kDefaultCigParams);
  }
}

// Check handling create cig request twice with the same CIG id
TEST_F(IsoManagerDeathTest, CreateSameCigTwice) {
  bluetooth::hci::iso_manager::cig_create_cmpl_evt evt;
  evt.status = 0x01;
  EXPECT_CALL(*cig_callbacks_, OnCigEvent(bluetooth::hci::iso_manager::kIsoEventCigOnCreateCmpl, _))
          .WillOnce([&evt](uint8_t /* type */, void* data) {
            evt = *static_cast<bluetooth::hci::iso_manager::cig_create_cmpl_evt*>(data);
            return 0;
          });

  volatile_test_cig_create_cmpl_evt_.cig_id = 127;
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);
  ASSERT_EQ(evt.status, HCI_SUCCESS);

  // Second call with the same CIG ID should fail
  ASSERT_EXIT(IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                                   kDefaultCigParams),
              ::testing::KilledBySignal(SIGABRT), "already exists");
}

// Check for handling invalid length response from the faulty controller
TEST_F(IsoManagerDeathTest, CreateCigCallbackInvalidRspPacket) {
  uint8_t hci_mock_rsp_buffer[] = {0x00, 0x00};
  ON_CALL(hcic_interface_, SetCigParams)
          .WillByDefault([&hci_mock_rsp_buffer](auto, auto,
                                                base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
            std::move(cb).Run(hci_mock_rsp_buffer, sizeof(hci_mock_rsp_buffer));
            return 0;
          });

  ASSERT_EXIT(IsoManager::GetInstance()->CreateCig(128, kDefaultCigParams),
              ::testing::KilledBySignal(SIGABRT), "Invalid packet length");
}

// Check for handling invalid length response from the faulty controller
TEST_F(IsoManagerDeathTest, CreateCigCallbackInvalidRspPacket2) {
  uint8_t hci_mock_rsp_buffer[] = {0x00, 0x00, 0x02, 0x01, 0x00};
  ON_CALL(hcic_interface_, SetCigParams)
          .WillByDefault([&hci_mock_rsp_buffer](auto, auto,
                                                base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
            std::move(cb).Run(hci_mock_rsp_buffer, sizeof(hci_mock_rsp_buffer));
            return 0;
          });

  ASSERT_EXIT(IsoManager::GetInstance()->CreateCig(128, kDefaultCigParams),
              ::testing::KilledBySignal(SIGABRT), "Invalid CIS count");
}

// Check if IsoManager properly handles error responses from HCI layer
TEST_F(IsoManagerTest, CreateCigCallbackInvalidStatus) {
  uint8_t rsp_cig_id = 128;
  uint8_t rsp_status = 0x01;
  uint8_t rsp_cis_cnt = 3;
  uint8_t hci_mock_rsp_buffer[] = {rsp_status, rsp_cig_id, rsp_cis_cnt};

  ON_CALL(hcic_interface_, SetCigParams)
          .WillByDefault([&hci_mock_rsp_buffer](auto, auto,
                                                base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
            std::move(cb).Run(hci_mock_rsp_buffer, sizeof(hci_mock_rsp_buffer));
            return 0;
          });

  bluetooth::hci::iso_manager::cig_create_cmpl_evt evt;
  EXPECT_CALL(*cig_callbacks_, OnCigEvent(bluetooth::hci::iso_manager::kIsoEventCigOnCreateCmpl, _))
          .WillOnce([&evt](uint8_t /* type */, void* data) {
            evt = *static_cast<bluetooth::hci::iso_manager::cig_create_cmpl_evt*>(data);
            return 0;
          });

  IsoManager::GetInstance()->CreateCig(rsp_cig_id, kDefaultCigParams);
  ASSERT_EQ(evt.cig_id, rsp_cig_id);
  ASSERT_EQ(evt.status, rsp_status);
  ASSERT_TRUE(evt.conn_handles.empty());
}

// Check valid callback response
TEST_F(IsoManagerTest, CreateCigCallbackValid) {
  bluetooth::hci::iso_manager::cig_create_cmpl_evt evt;
  EXPECT_CALL(*cig_callbacks_, OnCigEvent(bluetooth::hci::iso_manager::kIsoEventCigOnCreateCmpl, _))
          .WillOnce([&evt](uint8_t /* type */, void* data) {
            evt = *static_cast<bluetooth::hci::iso_manager::cig_create_cmpl_evt*>(data);
            return 0;
          });

  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);
  ASSERT_EQ(evt.cig_id, volatile_test_cig_create_cmpl_evt_.cig_id);
  ASSERT_EQ(evt.status, volatile_test_cig_create_cmpl_evt_.status);
  ASSERT_EQ(evt.conn_handles.size(), 2u);
  ASSERT_TRUE(std::is_permutation(evt.conn_handles.begin(), evt.conn_handles.end(),
                                  std::vector<uint16_t>({0x0EFF, 0x00FF}).begin()));
}

TEST_F(IsoManagerTest, CreateCigLateArrivingCallback) {
  // Catch the callback
  base::OnceCallback<void(uint8_t*, uint16_t)> iso_cb;
  ON_CALL(hcic_interface_, SetCigParams)
          .WillByDefault(
                  [&](auto /* cig_id */, auto, base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
                    iso_cb = std::move(cb);
                  });

  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);

  // Stop the IsoManager before calling the callback
  IsoManager::GetInstance()->Stop();

  // Call the callback and expect no call
  EXPECT_CALL(*cig_callbacks_, OnCigEvent(_, _)).Times(0);
  ASSERT_FALSE(iso_cb.is_null());

  uint8_t hci_mock_rsp_buffer[3 + sizeof(uint16_t) *
                                          volatile_test_cig_create_cmpl_evt_.conn_handles.size()];
  uint8_t* p = hci_mock_rsp_buffer;
  UINT8_TO_STREAM(p, volatile_test_cig_create_cmpl_evt_.status);
  UINT8_TO_STREAM(p, volatile_test_cig_create_cmpl_evt_.cig_id);
  UINT8_TO_STREAM(p, volatile_test_cig_create_cmpl_evt_.conn_handles.size());
  for (auto handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    UINT16_TO_STREAM(p, handle);
  }
  std::move(iso_cb).Run(
          hci_mock_rsp_buffer,
          3 + sizeof(uint16_t) * volatile_test_cig_create_cmpl_evt_.conn_handles.size());
}

// Check if CIG reconfigure triggers HCI layer call
TEST_F(IsoManagerTest, ReconfigureCigHciCall) {
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);

  EXPECT_CALL(hcic_interface_, SetCigParams(volatile_test_cig_create_cmpl_evt_.cig_id,
                                            iso_matchers::Eq(kDefaultCigParams), _))
          .Times(1);
  IsoManager::GetInstance()->ReconfigureCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                            kDefaultCigParams);
}

// Verify handlidng invalid call - reconfiguring invalid CIG
TEST_F(IsoManagerDeathTest, ReconfigureCigWithNoSuchCig) {
  ASSERT_EXIT(IsoManager::GetInstance()->ReconfigureCig(128, kDefaultCigParams),
              ::testing::KilledBySignal(SIGABRT), "No such cig");
}

TEST_F(IsoManagerDeathTest, ReconfigureCigInvalidRspPacket) {
  uint8_t hci_mock_rsp_buffer[] = {0x00, 0x00};

  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);

  ON_CALL(hcic_interface_, SetCigParams)
          .WillByDefault([&hci_mock_rsp_buffer](auto, auto,
                                                base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
            std::move(cb).Run(hci_mock_rsp_buffer, sizeof(hci_mock_rsp_buffer));
            return 0;
          });
  ASSERT_EXIT(IsoManager::GetInstance()->ReconfigureCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                                        kDefaultCigParams),
              ::testing::KilledBySignal(SIGABRT), "Invalid packet length");
}

TEST_F(IsoManagerDeathTest, ReconfigureCigInvalidRspPacket2) {
  uint8_t hci_mock_rsp_buffer[] = {0x00, 0x00, 0x02, 0x01, 0x00};

  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);

  ON_CALL(hcic_interface_, SetCigParams)
          .WillByDefault([&hci_mock_rsp_buffer](auto, auto,
                                                base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
            std::move(cb).Run(hci_mock_rsp_buffer, sizeof(hci_mock_rsp_buffer));
            return 0;
          });
  ASSERT_EXIT(IsoManager::GetInstance()->ReconfigureCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                                        kDefaultCigParams2),
              ::testing::KilledBySignal(SIGABRT), "Invalid CIS count");
}

TEST_F(IsoManagerTest, ReconfigureCigInvalidStatus) {
  uint8_t rsp_cig_id = 128;
  uint8_t rsp_status = 0x01;
  uint8_t rsp_cis_cnt = 3;
  uint8_t hci_mock_rsp_buffer[] = {rsp_status, rsp_cig_id, rsp_cis_cnt};

  IsoManager::GetInstance()->CreateCig(rsp_cig_id, kDefaultCigParams);

  // Set-up the invalid response
  ON_CALL(hcic_interface_, SetCigParams)
          .WillByDefault([&hci_mock_rsp_buffer](auto, auto,
                                                base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
            std::move(cb).Run(hci_mock_rsp_buffer, sizeof(hci_mock_rsp_buffer));
            return 0;
          });

  bluetooth::hci::iso_manager::cig_create_cmpl_evt evt;
  EXPECT_CALL(*cig_callbacks_,
              OnCigEvent(bluetooth::hci::iso_manager::kIsoEventCigOnReconfigureCmpl, _))
          .WillOnce([&evt](uint8_t /* type */, void* data) {
            evt = *static_cast<bluetooth::hci::iso_manager::cig_create_cmpl_evt*>(data);
            return 0;
          });
  IsoManager::GetInstance()->ReconfigureCig(rsp_cig_id, kDefaultCigParams2);

  ASSERT_EQ(evt.cig_id, rsp_cig_id);
  ASSERT_EQ(evt.status, rsp_status);
  ASSERT_TRUE(evt.conn_handles.empty());
}

TEST_F(IsoManagerTest, ReconfigureCigValid) {
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);

  bluetooth::hci::iso_manager::cig_create_cmpl_evt evt;
  EXPECT_CALL(*cig_callbacks_,
              OnCigEvent(bluetooth::hci::iso_manager::kIsoEventCigOnReconfigureCmpl, _))
          .WillOnce([&evt](uint8_t /* type */, void* data) {
            evt = *static_cast<bluetooth::hci::iso_manager::cig_create_cmpl_evt*>(data);
            return 0;
          });

  // Verify valid reconfiguration request
  IsoManager::GetInstance()->ReconfigureCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                            kDefaultCigParams2);
  ASSERT_EQ(evt.cig_id, volatile_test_cig_create_cmpl_evt_.cig_id);
  ASSERT_EQ(evt.status, volatile_test_cig_create_cmpl_evt_.status);
  ASSERT_TRUE(std::is_permutation(evt.conn_handles.begin(), evt.conn_handles.end(),
                                  volatile_test_cig_create_cmpl_evt_.conn_handles.begin()));
}

TEST_F(IsoManagerTest, ReconfigureCigLateArrivingCallback) {
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);

  // Catch the callback
  base::OnceCallback<void(uint8_t*, uint16_t)> iso_cb;
  ON_CALL(hcic_interface_, SetCigParams)
          .WillByDefault(
                  [&](auto /* cig_id */, auto, base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
                    iso_cb = std::move(cb);
                  });
  IsoManager::GetInstance()->ReconfigureCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                            kDefaultCigParams2);

  // Stop the IsoManager before calling the callback
  IsoManager::GetInstance()->Stop();

  // Call the callback and expect no call
  EXPECT_CALL(*cig_callbacks_, OnCigEvent(_, _)).Times(0);
  ASSERT_FALSE(iso_cb.is_null());

  uint8_t hci_mock_rsp_buffer[3 + sizeof(uint16_t) *
                                          volatile_test_cig_create_cmpl_evt_.conn_handles.size()];
  uint8_t* p = hci_mock_rsp_buffer;
  UINT8_TO_STREAM(p, volatile_test_cig_create_cmpl_evt_.status);
  UINT8_TO_STREAM(p, volatile_test_cig_create_cmpl_evt_.cig_id);
  UINT8_TO_STREAM(p, volatile_test_cig_create_cmpl_evt_.conn_handles.size());
  for (auto handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    UINT16_TO_STREAM(p, handle);
  }
  std::move(iso_cb).Run(
          hci_mock_rsp_buffer,
          3 + sizeof(uint16_t) * volatile_test_cig_create_cmpl_evt_.conn_handles.size());
}

TEST_F(IsoManagerTest, RemoveCigHciCall) {
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);

  EXPECT_CALL(hcic_interface_, RemoveCig(volatile_test_cig_create_cmpl_evt_.cig_id, _)).Times(1);
  IsoManager::GetInstance()->RemoveCig(volatile_test_cig_create_cmpl_evt_.cig_id);
}

TEST_F(IsoManagerDeathTest, RemoveCigWithNoSuchCig) {
  ASSERT_EXIT(IsoManager::GetInstance()->RemoveCig(volatile_test_cig_create_cmpl_evt_.cig_id),
              ::testing::KilledBySignal(SIGABRT), "No such cig");
}

TEST_F(IsoManagerDeathTest, RemoveCigForceNoSuchCig) {
  EXPECT_CALL(hcic_interface_, RemoveCig(volatile_test_cig_create_cmpl_evt_.cig_id, _)).Times(1);
  IsoManager::GetInstance()->RemoveCig(volatile_test_cig_create_cmpl_evt_.cig_id, true);
}

TEST_F(IsoManagerDeathTest, RemoveSameCigTwice) {
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);

  ON_CALL(hcic_interface_, RemoveCig)
          .WillByDefault([this](auto, base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
            uint8_t hci_mock_rsp_buffer[2];
            uint8_t* p = hci_mock_rsp_buffer;

            UINT8_TO_STREAM(p, HCI_SUCCESS);
            UINT8_TO_STREAM(p, this->volatile_test_cig_create_cmpl_evt_.cig_id);

            std::move(cb).Run(hci_mock_rsp_buffer, sizeof(hci_mock_rsp_buffer));
            return 0;
          });

  IsoManager::GetInstance()->RemoveCig(volatile_test_cig_create_cmpl_evt_.cig_id);

  ASSERT_EXIT(IsoManager::GetInstance()->RemoveCig(volatile_test_cig_create_cmpl_evt_.cig_id),
              ::testing::KilledBySignal(SIGABRT), "No such cig");
}

TEST_F(IsoManagerDeathTest, RemoveCigInvalidRspPacket) {
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);

  ON_CALL(hcic_interface_, RemoveCig)
          .WillByDefault([](auto, base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
            uint8_t hci_mock_rsp_buffer[] = {0x00};  // status byte only

            std::move(cb).Run(hci_mock_rsp_buffer, sizeof(hci_mock_rsp_buffer));
            return 0;
          });
  ASSERT_EXIT(IsoManager::GetInstance()->RemoveCig(volatile_test_cig_create_cmpl_evt_.cig_id),
              ::testing::KilledBySignal(SIGABRT), "Invalid packet length");
}

TEST_F(IsoManagerTest, RemoveCigInvalidStatus) {
  uint8_t rsp_status = 0x02;
  uint8_t hci_mock_rsp_buffer[] = {rsp_status, volatile_test_cig_create_cmpl_evt_.cig_id};

  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);

  ON_CALL(hcic_interface_, RemoveCig)
          .WillByDefault(
                  [&hci_mock_rsp_buffer](auto, base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
                    std::move(cb).Run(hci_mock_rsp_buffer, sizeof(hci_mock_rsp_buffer));
                    return 0;
                  });

  bluetooth::hci::iso_manager::cig_remove_cmpl_evt evt;
  ON_CALL(*cig_callbacks_, OnCigEvent(bluetooth::hci::iso_manager::kIsoEventCigOnRemoveCmpl, _))
          .WillByDefault([&evt](uint8_t /* type */, void* data) {
            evt = *static_cast<bluetooth::hci::iso_manager::cig_remove_cmpl_evt*>(data);
            return 0;
          });

  IsoManager::GetInstance()->RemoveCig(volatile_test_cig_create_cmpl_evt_.cig_id);
  ASSERT_EQ(evt.cig_id, volatile_test_cig_create_cmpl_evt_.cig_id);
  ASSERT_EQ(evt.status, rsp_status);
}

TEST_F(IsoManagerTest, RemoveCigValid) {
  uint8_t hci_mock_rsp_buffer[] = {HCI_SUCCESS, volatile_test_cig_create_cmpl_evt_.cig_id};

  ASSERT_EQ(IsIsoActive, false);
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);
  ASSERT_EQ(IsIsoActive, true);

  ON_CALL(hcic_interface_, RemoveCig)
          .WillByDefault(
                  [&hci_mock_rsp_buffer](auto, base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
                    std::move(cb).Run(hci_mock_rsp_buffer, sizeof(hci_mock_rsp_buffer));
                    return 0;
                  });

  bluetooth::hci::iso_manager::cig_remove_cmpl_evt evt;
  EXPECT_CALL(*cig_callbacks_, OnCigEvent(bluetooth::hci::iso_manager::kIsoEventCigOnRemoveCmpl, _))
          .WillOnce([&evt](uint8_t /* type */, void* data) {
            evt = *static_cast<bluetooth::hci::iso_manager::cig_remove_cmpl_evt*>(data);
            return 0;
          });

  IsoManager::GetInstance()->RemoveCig(volatile_test_cig_create_cmpl_evt_.cig_id);
  ASSERT_EQ(evt.cig_id, volatile_test_cig_create_cmpl_evt_.cig_id);
  ASSERT_EQ(evt.status, HCI_SUCCESS);
  ASSERT_EQ(IsIsoActive, false);
}

TEST_F(IsoManagerTest, EstablishCisHciCall) {
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);

  bluetooth::hci::iso_manager::cis_establish_params params;
  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    params.conn_pairs.push_back({handle, 1});
  }

  EXPECT_CALL(hcic_interface_,
              CreateCis(2,
                        iso_matchers::EqPointedArray(
                                params.conn_pairs.data(),
                                params.conn_pairs.size() * sizeof(params.conn_pairs.data()[0])),
                        _))
          .Times(1);
  IsoManager::GetInstance()->EstablishCis(params);
}

TEST_F(IsoManagerDeathTest, EstablishCisWithNoSuchCis) {
  bluetooth::hci::iso_manager::cis_establish_params params;
  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    params.conn_pairs.push_back({handle, 1});
  }

  ASSERT_EXIT(IsoManager::GetInstance()->IsoManager::GetInstance()->EstablishCis(params),
              ::testing::KilledBySignal(SIGABRT), "No such cis");
}

TEST_F(IsoManagerDeathTest, ConnectSameCisTwice) {
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);

  bluetooth::hci::iso_manager::cis_establish_params params;
  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    params.conn_pairs.push_back({handle, 1});
  }
  IsoManager::GetInstance()->EstablishCis(params);

  ASSERT_EXIT(IsoManager::GetInstance()->IsoManager::GetInstance()->EstablishCis(params),
              ::testing::KilledBySignal(SIGABRT), "already connected/connecting/cancelled");
}

TEST_F(IsoManagerDeathTest, EstablishCisInvalidResponsePacket) {
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);

  ON_CALL(hcic_interface_, CreateCis)
          .WillByDefault([this](uint8_t /* num_cis */, const EXT_CIS_CREATE_CFG* /* cis_cfg */,
                                base::OnceCallback<void(uint8_t*, uint16_t)> /* cb */) {
            for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
              std::vector<uint8_t> buf(27);
              uint8_t* p = buf.data();
              UINT8_TO_STREAM(p, HCI_SUCCESS);
              UINT16_TO_STREAM(p, handle);
              UINT24_TO_STREAM(p, 0xEA);    // CIG sync delay
              UINT24_TO_STREAM(p, 0xEB);    // CIS sync delay
              UINT24_TO_STREAM(p, 0xEC);    // transport latency mtos
              UINT24_TO_STREAM(p, 0xED);    // transport latency stom
              UINT8_TO_STREAM(p, 0x01);     // phy mtos
              UINT8_TO_STREAM(p, 0x02);     // phy stom
              UINT8_TO_STREAM(p, 0x01);     // nse
              UINT8_TO_STREAM(p, 0x02);     // bn mtos
              UINT8_TO_STREAM(p, 0x03);     // bn stom
              UINT8_TO_STREAM(p, 0x04);     // ft mtos
              UINT8_TO_STREAM(p, 0x05);     // ft stom
              UINT16_TO_STREAM(p, 0x00FA);  // Max PDU mtos
              UINT16_TO_STREAM(p, 0x00FB);  // Max PDU stom

              IsoManager::GetInstance()->HandleHciEvent(HCI_BLE_CIS_EST_EVT, buf.data(),
                                                        buf.size());
            }
          });

  bluetooth::hci::iso_manager::cis_establish_params params;
  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    params.conn_pairs.push_back({handle, 1});
  }

  ASSERT_EXIT(IsoManager::GetInstance()->IsoManager::GetInstance()->EstablishCis(params),
              ::testing::KilledBySignal(SIGABRT), "Invalid packet length");
}

TEST_F(IsoManagerTest, EstablishCisInvalidCommandStatus) {
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);
  uint16_t invalid_status = 0x0001;

  ON_CALL(hcic_interface_, CreateCis)
          .WillByDefault([invalid_status](uint8_t /* num_cis */,
                                          const EXT_CIS_CREATE_CFG* /* cis_cfg */,
                                          base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
            std::move(cb).Run((uint8_t*)&invalid_status, sizeof(invalid_status));
            return 0;
          });

  EXPECT_CALL(*cig_callbacks_,
              OnCisEvent(bluetooth::hci::iso_manager::kIsoEventCisEstablishCmpl, _))
          .Times(kDefaultCigParams.cis_cfgs.size())
          .WillRepeatedly([this, invalid_status](uint8_t /* type */, void* data) {
            bluetooth::hci::iso_manager::cis_establish_cmpl_evt* evt =
                    static_cast<bluetooth::hci::iso_manager::cis_establish_cmpl_evt*>(data);

            ASSERT_EQ(evt->status, invalid_status);
            ASSERT_TRUE(std::find(volatile_test_cig_create_cmpl_evt_.conn_handles.begin(),
                                  volatile_test_cig_create_cmpl_evt_.conn_handles.end(),
                                  evt->cis_conn_hdl) !=
                        volatile_test_cig_create_cmpl_evt_.conn_handles.end());
          });

  // Establish all CISes
  bluetooth::hci::iso_manager::cis_establish_params params;
  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    params.conn_pairs.push_back({handle, 1});
  }
  IsoManager::GetInstance()->EstablishCis(params);
}

TEST_F(IsoManagerTest, EstablishCisInvalidStatus) {
  uint8_t cig_id = volatile_test_cig_create_cmpl_evt_.cig_id;
  IsoManager::GetInstance()->CreateCig(cig_id, kDefaultCigParams);
  uint8_t invalid_status = 0x01;

  ON_CALL(hcic_interface_, CreateCis)
          .WillByDefault([this, invalid_status](
                                 uint8_t /* num_cis */, const EXT_CIS_CREATE_CFG* /* cis_cfg */,
                                 base::OnceCallback<void(uint8_t*, uint16_t)> /* cb */) {
            for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
              std::vector<uint8_t> buf(28);
              uint8_t* p = buf.data();
              UINT8_TO_STREAM(p, invalid_status);
              UINT16_TO_STREAM(p, handle);
              UINT24_TO_STREAM(p, 0xEA);    // CIG sync delay
              UINT24_TO_STREAM(p, 0xEB);    // CIS sync delay
              UINT24_TO_STREAM(p, 0xEC);    // transport latency mtos
              UINT24_TO_STREAM(p, 0xED);    // transport latency stom
              UINT8_TO_STREAM(p, 0x01);     // phy mtos
              UINT8_TO_STREAM(p, 0x02);     // phy stom
              UINT8_TO_STREAM(p, 0x01);     // nse
              UINT8_TO_STREAM(p, 0x02);     // bn mtos
              UINT8_TO_STREAM(p, 0x03);     // bn stom
              UINT8_TO_STREAM(p, 0x04);     // ft mtos
              UINT8_TO_STREAM(p, 0x05);     // ft stom
              UINT16_TO_STREAM(p, 0x00FA);  // Max PDU mtos
              UINT16_TO_STREAM(p, 0x00FB);  // Max PDU stom
              UINT16_TO_STREAM(p, 0x0C60);  // ISO interval

              IsoManager::GetInstance()->HandleHciEvent(HCI_BLE_CIS_EST_EVT, buf.data(),
                                                        buf.size());
            }
          });

  EXPECT_CALL(*cig_callbacks_,
              OnCisEvent(bluetooth::hci::iso_manager::kIsoEventCisEstablishCmpl, _))
          .Times(kDefaultCigParams.cis_cfgs.size())
          .WillRepeatedly([this, invalid_status, cig_id](uint8_t /* type */, void* data) {
            bluetooth::hci::iso_manager::cis_establish_cmpl_evt* evt =
                    static_cast<bluetooth::hci::iso_manager::cis_establish_cmpl_evt*>(data);

            ASSERT_EQ(evt->status, invalid_status);
            ASSERT_EQ(evt->cig_id, cig_id);
            ASSERT_TRUE(std::find(volatile_test_cig_create_cmpl_evt_.conn_handles.begin(),
                                  volatile_test_cig_create_cmpl_evt_.conn_handles.end(),
                                  evt->cis_conn_hdl) !=
                        volatile_test_cig_create_cmpl_evt_.conn_handles.end());
          });

  // Establish all CISes before setting up their data paths
  bluetooth::hci::iso_manager::cis_establish_params params;
  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    params.conn_pairs.push_back({handle, 1});
  }
  IsoManager::GetInstance()->EstablishCis(params);
}

TEST_F(IsoManagerTest, EstablishCisValid) {
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);

  EXPECT_CALL(*cig_callbacks_,
              OnCisEvent(bluetooth::hci::iso_manager::kIsoEventCisEstablishCmpl, _))
          .Times(kDefaultCigParams.cis_cfgs.size())
          .WillRepeatedly([this](uint8_t /* type */, void* data) {
            bluetooth::hci::iso_manager::cis_establish_cmpl_evt* evt =
                    static_cast<bluetooth::hci::iso_manager::cis_establish_cmpl_evt*>(data);

            ASSERT_EQ(evt->status, HCI_SUCCESS);
            ASSERT_TRUE(std::find(volatile_test_cig_create_cmpl_evt_.conn_handles.begin(),
                                  volatile_test_cig_create_cmpl_evt_.conn_handles.end(),
                                  evt->cis_conn_hdl) !=
                        volatile_test_cig_create_cmpl_evt_.conn_handles.end());
          });

  // Establish all CISes before setting up their data paths
  bluetooth::hci::iso_manager::cis_establish_params params;
  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    params.conn_pairs.push_back({handle, 1});
  }
  IsoManager::GetInstance()->EstablishCis(params);
}

TEST_F(IsoManagerTest, EstablishCisLateArrivingCallback) {
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);

  // Catch the callback
  base::OnceCallback<void(uint8_t*, uint16_t)> iso_cb;
  EXT_CIS_CREATE_CFG cis_create_cfg;
  uint8_t cis_num = 0;
  ON_CALL(hcic_interface_, CreateCis)
          .WillByDefault([&](uint8_t num_cis, const EXT_CIS_CREATE_CFG* cis_cfg,
                             base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
            cis_create_cfg = *cis_cfg;
            cis_num = num_cis;
            iso_cb = std::move(cb);
          });

  // Establish all CISes before setting up their data paths
  bluetooth::hci::iso_manager::cis_establish_params params;
  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    params.conn_pairs.push_back({handle, 1});
  }
  IsoManager::GetInstance()->EstablishCis(params);

  // Stop the IsoManager before calling the callback
  IsoManager::GetInstance()->Stop();

  // Call the callback and expect no call
  EXPECT_CALL(*cig_callbacks_,
              OnCisEvent(bluetooth::hci::iso_manager::kIsoEventCisEstablishCmpl, _))
          .Times(0);
  ASSERT_FALSE(iso_cb.is_null());

  // Command complete with error will trigger the callback without
  // injecting any additional HCI events
  std::vector<uint8_t> buf(1);
  uint8_t* p = buf.data();
  UINT8_TO_STREAM(p, 0x01);  // status
  std::move(iso_cb).Run(buf.data(), buf.size());
}

TEST_F(IsoManagerTest, CancelPendingCreateCis_EstablishedThenDisconnected) {
  /**
   * Verify the HCI Disconnect command will cancel pending CIS creation.
   * As the Core is not strict about event order, in this scenario HCI CIS Established event comes
   * before HCI Disconnection Complete event.
   *
   * Scenario:
   * 1. Issue the HCI LE Create CIS command.
   * 2. Issue HCI Disconnect command with CIS connection handle parameter before the HCI CIS
   *    Established event is received.
   * 3. Verify the kIsoEventCisEstablishCmpl event is generated once HCI CIS Established event is
   *    received with Operation Cancelled By Local Host error.
   * 4. Verify the kIsoEventCisDisconnected event is generated once HCI Disconnection Complete event
   *    is received.
   */

  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);
  ON_CALL(hcic_interface_, CreateCis)
          .WillByDefault([](uint8_t, const EXT_CIS_CREATE_CFG*,
                            base::OnceCallback<void(uint8_t*, uint16_t)> /* cb */) {
            /* We override default mock. Nothing to do here */
          });

  ON_CALL(hcic_interface_, Disconnect).WillByDefault([](uint16_t, uint8_t) {
    /* We override default mock. Nothing to do here */
  });

  EXPECT_CALL(*cig_callbacks_,
              OnCisEvent(bluetooth::hci::iso_manager::kIsoEventCisEstablishCmpl, _))
          .Times(kDefaultCigParams.cis_cfgs.size())
          .WillRepeatedly([this](uint8_t /* type */, void* data) {
            auto* event = static_cast<bluetooth::hci::iso_manager::cis_establish_cmpl_evt*>(data);
            ASSERT_EQ(event->status, HCI_ERR_CANCELLED_BY_LOCAL_HOST);
            ASSERT_EQ(event->cig_id, volatile_test_cig_create_cmpl_evt_.cig_id);
            ASSERT_TRUE(std::find(volatile_test_cig_create_cmpl_evt_.conn_handles.begin(),
                                  volatile_test_cig_create_cmpl_evt_.conn_handles.end(),
                                  event->cis_conn_hdl) !=
                        volatile_test_cig_create_cmpl_evt_.conn_handles.end());
          });

  EXPECT_CALL(*cig_callbacks_, OnCisEvent(bluetooth::hci::iso_manager::kIsoEventCisDisconnected, _))
          .Times(kDefaultCigParams.cis_cfgs.size())
          .WillRepeatedly([this](uint8_t /* type */, void* data) {
            auto* event = static_cast<bluetooth::hci::iso_manager::cis_disconnected_evt*>(data);
            ASSERT_EQ(event->reason, HCI_ERR_CONN_CAUSE_LOCAL_HOST);
            ASSERT_EQ(event->cig_id, volatile_test_cig_create_cmpl_evt_.cig_id);
            ASSERT_TRUE(std::find(volatile_test_cig_create_cmpl_evt_.conn_handles.begin(),
                                  volatile_test_cig_create_cmpl_evt_.conn_handles.end(),
                                  event->cis_conn_hdl) !=
                        volatile_test_cig_create_cmpl_evt_.conn_handles.end());
          });

  EXPECT_CALL(hcic_interface_, CreateCis).Times(1);

  // Establish all CISes before setting up their data paths
  bluetooth::hci::iso_manager::cis_establish_params params;
  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    params.conn_pairs.push_back({handle, 1});
  }
  IsoManager::GetInstance()->EstablishCis(params);

  EXPECT_CALL(hcic_interface_, Disconnect).Times(kDefaultCigParams.cis_cfgs.size());

  /* Cancel pending HCI LE Create CIS command */
  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    IsoManager::GetInstance()->DisconnectCis(handle, HCI_ERR_CONN_CAUSE_LOCAL_HOST);
  }

  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    std::vector<uint8_t> buf(28, 0);
    uint8_t* p = buf.data();
    UINT8_TO_STREAM(p, HCI_ERR_CANCELLED_BY_LOCAL_HOST);
    UINT16_TO_STREAM(p, handle);

    /* inject HCI LE CIS Established event */
    IsoManager::GetInstance()->HandleHciEvent(HCI_BLE_CIS_EST_EVT, buf.data(), buf.size());

    /* followed by HCI Disconnection Complete event */
    IsoManager::GetInstance()->HandleDisconnect(handle, HCI_ERR_CONN_CAUSE_LOCAL_HOST);
  }
}

TEST_F(IsoManagerTest, CancelPendingCreateCis_DisconnectedThenEstablished) {
  /**
   * Verify the HCI Disconnect command will cancel pending CIS creation.
   * As the Core is not strict about event order, in this scenario HCI Disconnection Complete event
   * comes before HCI CIS Established event.
   *
   * Scenario:
   * 1. Issue the HCI LE Create CIS command.
   * 2. Issue HCI Disconnect command with CIS connection handle parameter before the HCI CIS
   *    Established event is received.
   * 3. Verify the kIsoEventCisEstablishCmpl event is generated once HCI CIS Established event is
   *    received with Operation Cancelled By Local Host error.
   * 4. Verify the kIsoEventCisDisconnected event is generated once HCI Disconnection Complete event
   *    is received.
   */

  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);
  ON_CALL(hcic_interface_, CreateCis)
          .WillByDefault([](uint8_t, const EXT_CIS_CREATE_CFG*,
                            base::OnceCallback<void(uint8_t*, uint16_t)> /* cb */) {
            /* We override default mock. Nothing to do here */
          });

  ON_CALL(hcic_interface_, Disconnect).WillByDefault([](uint16_t, uint8_t) {
    /* We override default mock. Nothing to do here */
  });

  EXPECT_CALL(*cig_callbacks_,
              OnCisEvent(bluetooth::hci::iso_manager::kIsoEventCisEstablishCmpl, _))
          .Times(kDefaultCigParams.cis_cfgs.size())
          .WillRepeatedly([this](uint8_t /* type */, void* data) {
            auto* event = static_cast<bluetooth::hci::iso_manager::cis_establish_cmpl_evt*>(data);
            ASSERT_EQ(event->status, HCI_ERR_CANCELLED_BY_LOCAL_HOST);
            ASSERT_EQ(event->cig_id, volatile_test_cig_create_cmpl_evt_.cig_id);
            ASSERT_TRUE(std::find(volatile_test_cig_create_cmpl_evt_.conn_handles.begin(),
                                  volatile_test_cig_create_cmpl_evt_.conn_handles.end(),
                                  event->cis_conn_hdl) !=
                        volatile_test_cig_create_cmpl_evt_.conn_handles.end());
          });

  EXPECT_CALL(*cig_callbacks_, OnCisEvent(bluetooth::hci::iso_manager::kIsoEventCisDisconnected, _))
          .Times(kDefaultCigParams.cis_cfgs.size())
          .WillRepeatedly([this](uint8_t /* type */, void* data) {
            auto* event = static_cast<bluetooth::hci::iso_manager::cis_disconnected_evt*>(data);
            ASSERT_EQ(event->reason, HCI_ERR_CONN_CAUSE_LOCAL_HOST);
            ASSERT_EQ(event->cig_id, volatile_test_cig_create_cmpl_evt_.cig_id);
            ASSERT_TRUE(std::find(volatile_test_cig_create_cmpl_evt_.conn_handles.begin(),
                                  volatile_test_cig_create_cmpl_evt_.conn_handles.end(),
                                  event->cis_conn_hdl) !=
                        volatile_test_cig_create_cmpl_evt_.conn_handles.end());
          });

  EXPECT_CALL(hcic_interface_, CreateCis).Times(1);

  // Establish all CISes before setting up their data paths
  bluetooth::hci::iso_manager::cis_establish_params params;
  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    params.conn_pairs.push_back({handle, 1});
  }
  IsoManager::GetInstance()->EstablishCis(params);

  EXPECT_CALL(hcic_interface_, Disconnect).Times(kDefaultCigParams.cis_cfgs.size());

  /* Cancel pending HCI LE Create CIS command */
  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    IsoManager::GetInstance()->DisconnectCis(handle, HCI_ERR_CONN_CAUSE_LOCAL_HOST);
  }

  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    /* inject HCI Disconnection Complete event */
    IsoManager::GetInstance()->HandleDisconnect(handle, HCI_ERR_CONN_CAUSE_LOCAL_HOST);

    std::vector<uint8_t> buf(28, 0);
    uint8_t* p = buf.data();
    UINT8_TO_STREAM(p, HCI_ERR_CANCELLED_BY_LOCAL_HOST);
    UINT16_TO_STREAM(p, handle);

    /* followed by inject HCI LE CIS Established event */
    IsoManager::GetInstance()->HandleHciEvent(HCI_BLE_CIS_EST_EVT, buf.data(), buf.size());
  }
}

TEST_F(IsoManagerTest, ReconnectCisValid) {
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);

  // Establish all CISes before setting up their data paths
  bluetooth::hci::iso_manager::cis_establish_params params;
  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    params.conn_pairs.push_back({handle, 1});
  }
  IsoManager::GetInstance()->EstablishCis(params);

  // trigger HCI disconnection event
  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    IsoManager::GetInstance()->HandleDisconnect(handle, 0x16);
  }

  EXPECT_CALL(*cig_callbacks_,
              OnCisEvent(bluetooth::hci::iso_manager::kIsoEventCisEstablishCmpl, _))
          .Times(kDefaultCigParams.cis_cfgs.size())
          .WillRepeatedly([this](uint8_t /* type */, void* data) {
            bluetooth::hci::iso_manager::cis_establish_cmpl_evt* evt =
                    static_cast<bluetooth::hci::iso_manager::cis_establish_cmpl_evt*>(data);

            ASSERT_EQ(evt->status, HCI_SUCCESS);
            ASSERT_TRUE(std::find(volatile_test_cig_create_cmpl_evt_.conn_handles.begin(),
                                  volatile_test_cig_create_cmpl_evt_.conn_handles.end(),
                                  evt->cis_conn_hdl) !=
                        volatile_test_cig_create_cmpl_evt_.conn_handles.end());
          });
  IsoManager::GetInstance()->EstablishCis(params);
}

TEST_F(IsoManagerTest, DisconnectCisHciCall) {
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);

  // Establish all CISes before setting up their data paths
  bluetooth::hci::iso_manager::cis_establish_params params;
  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    params.conn_pairs.push_back({handle, 1});
  }
  IsoManager::GetInstance()->EstablishCis(params);

  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    EXPECT_CALL(hcic_interface_, Disconnect(handle, 0x16)).Times(1).RetiresOnSaturation();
    IsoManager::GetInstance()->IsoManager::GetInstance()->DisconnectCis(handle, 0x16);
  }
}

TEST_F(IsoManagerDeathTest, DisconnectCisWithNoSuchCis) {
  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    ASSERT_EXIT(IsoManager::GetInstance()->IsoManager::GetInstance()->DisconnectCis(handle, 0x16),
                ::testing::KilledBySignal(SIGABRT), "No such cis");
  }
}

TEST_F(IsoManagerDeathTest, DisconnectSameCisTwice) {
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);

  // Establish all CISes before setting up their data paths
  bluetooth::hci::iso_manager::cis_establish_params params;
  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    params.conn_pairs.push_back({handle, 1});
  }
  IsoManager::GetInstance()->EstablishCis(params);

  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    IsoManager::GetInstance()->IsoManager::GetInstance()->DisconnectCis(handle, 0x16);
  }

  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    ASSERT_EXIT(IsoManager::GetInstance()->IsoManager::GetInstance()->DisconnectCis(handle, 0x16),
                ::testing::KilledBySignal(SIGABRT), "Not connected");
  }
}

TEST_F(IsoManagerTest, DisconnectCisValid) {
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);

  // Establish all CISes before setting up their data paths
  bluetooth::hci::iso_manager::cis_establish_params params;
  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    params.conn_pairs.push_back({handle, 1});
  }
  IsoManager::GetInstance()->EstablishCis(params);

  uint8_t disconnect_reason = 0x16;
  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    EXPECT_CALL(*cig_callbacks_, OnCisEvent)
            .WillOnce([this, handle, disconnect_reason](uint8_t event_code, void* data) {
              ASSERT_EQ(event_code, bluetooth::hci::iso_manager::kIsoEventCisDisconnected);
              auto* event = static_cast<bluetooth::hci::iso_manager::cis_disconnected_evt*>(data);
              ASSERT_EQ(event->reason, disconnect_reason);
              ASSERT_EQ(event->cig_id, volatile_test_cig_create_cmpl_evt_.cig_id);
              ASSERT_EQ(event->cis_conn_hdl, handle);
            })
            .RetiresOnSaturation();
    IsoManager::GetInstance()->IsoManager::GetInstance()->DisconnectCis(handle, disconnect_reason);
  }
}

// Check if we properly ignore not ISO related disconnect events
TEST_F(IsoManagerDeathTest, DisconnectCisInvalidResponse) {
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);

  bluetooth::hci::iso_manager::cis_establish_params params;
  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    params.conn_pairs.push_back({handle, 1});
  }
  IsoManager::GetInstance()->EstablishCis(params);

  // Make the HCI layer send invalid handles in disconnect event
  ON_CALL(hcic_interface_, Disconnect).WillByDefault([](uint16_t handle, uint8_t reason) {
    IsoManager::GetInstance()->HandleDisconnect(handle + 1, reason);
  });

  // We don't expect any calls as these are not ISO handles
  ON_CALL(*cig_callbacks_, OnCisEvent(bluetooth::hci::iso_manager::kIsoEventCisDisconnected, _))
          .WillByDefault([](uint8_t /* event_code */, void* /* data */) { FAIL(); });

  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    IsoManager::GetInstance()->IsoManager::GetInstance()->DisconnectCis(handle, 0x16);
  }
}

TEST_F(IsoManagerTest, CreateBigHciCall) {
  for (uint8_t i = 220; i != 60; ++i) {
    EXPECT_CALL(hcic_interface_, CreateBig(i, iso_matchers::Eq(kDefaultBigParams)))
            .Times(1)
            .RetiresOnSaturation();
    IsoManager::GetInstance()->CreateBig(i, kDefaultBigParams);
  }
}

TEST_F(IsoManagerTest, CreateBigValid) {
  bluetooth::hci::iso_manager::big_create_cmpl_evt evt;
  evt.status = 0x01;
  EXPECT_CALL(*big_callbacks_, OnBigEvent(bluetooth::hci::iso_manager::kIsoEventBigOnCreateCmpl, _))
          .WillOnce([&evt](uint8_t /* type */, void* data) {
            evt = *static_cast<bluetooth::hci::iso_manager::big_create_cmpl_evt*>(data);
            return 0;
          });

  IsoManager::GetInstance()->CreateBig(0x01, kDefaultBigParams);
  ASSERT_EQ(evt.status, HCI_SUCCESS);
}

TEST_F(IsoManagerDeathTest, CreateBigInvalidResponsePacket) {
  ON_CALL(hcic_interface_, CreateBig)
          .WillByDefault(
                  [](auto big_handle, bluetooth::hci::iso_manager::big_create_params big_params) {
                    std::vector<uint8_t> buf(18);
                    uint8_t* p = buf.data();
                    UINT8_TO_STREAM(p, 0x00);
                    UINT8_TO_STREAM(p, big_handle);

                    UINT24_TO_STREAM(p, 0x0080de);       // big_sync_delay
                    UINT24_TO_STREAM(p, 0x00cefe);       // transport_latency_big
                    UINT8_TO_STREAM(p, big_params.phy);  // phy
                    UINT8_TO_STREAM(p, 4);               // nse
                    UINT8_TO_STREAM(p, 1);               // bn
                    UINT8_TO_STREAM(p, 0);               // pto
                    UINT8_TO_STREAM(p, 4);               // irc
                    UINT16_TO_STREAM(p, 108);            // max_pdu
                    UINT16_TO_STREAM(p, 6);              // iso_interval
                    UINT8_TO_STREAM(p, 0);               // num BISes

                    IsoManager::GetInstance()->HandleHciEvent(HCI_BLE_CREATE_BIG_CPL_EVT,
                                                              buf.data(), buf.size());
                  });

  ASSERT_EXIT(IsoManager::GetInstance()->CreateBig(0x01, kDefaultBigParams),
              ::testing::KilledBySignal(SIGABRT), "Bis count is 0");
}

TEST_F(IsoManagerDeathTest, CreateBigInvalidResponsePacket2) {
  ON_CALL(hcic_interface_, CreateBig)
          .WillByDefault(
                  [](auto big_handle, bluetooth::hci::iso_manager::big_create_params big_params) {
                    std::vector<uint8_t> buf(18);
                    uint8_t* p = buf.data();
                    UINT8_TO_STREAM(p, 0x00);
                    UINT8_TO_STREAM(p, big_handle);

                    UINT24_TO_STREAM(p, 0x0080de);       // big_sync_delay
                    UINT24_TO_STREAM(p, 0x00cefe);       // transport_latency_big
                    UINT8_TO_STREAM(p, big_params.phy);  // phy
                    UINT8_TO_STREAM(p, 4);               // nse
                    UINT8_TO_STREAM(p, 1);               // bn
                    UINT8_TO_STREAM(p, 0);               // pto
                    UINT8_TO_STREAM(p, 4);               // irc
                    UINT16_TO_STREAM(p, 108);            // max_pdu
                    UINT16_TO_STREAM(p, 6);              // iso_interval
                    UINT8_TO_STREAM(p, big_params.num_bis);

                    IsoManager::GetInstance()->HandleHciEvent(HCI_BLE_CREATE_BIG_CPL_EVT,
                                                              buf.data(), buf.size());
                  });

  ASSERT_EXIT(IsoManager::GetInstance()->CreateBig(0x01, kDefaultBigParams),
              ::testing::KilledBySignal(SIGABRT), "Invalid packet length");
}

TEST_F(IsoManagerTest, CreateBigInvalidStatus) {
  bluetooth::hci::iso_manager::big_create_cmpl_evt evt;
  evt.status = 0x00;
  EXPECT_CALL(*big_callbacks_, OnBigEvent(bluetooth::hci::iso_manager::kIsoEventBigOnCreateCmpl, _))
          .WillOnce([&evt](uint8_t /* type */, void* data) {
            evt = *static_cast<bluetooth::hci::iso_manager::big_create_cmpl_evt*>(data);
            return 0;
          });

  ON_CALL(hcic_interface_, CreateBig)
          .WillByDefault(
                  [](auto big_handle, bluetooth::hci::iso_manager::big_create_params big_params) {
                    std::vector<uint8_t> buf(big_params.num_bis * sizeof(uint16_t) + 18);
                    uint8_t* p = buf.data();
                    UINT8_TO_STREAM(p, 0x01);
                    UINT8_TO_STREAM(p, big_handle);

                    UINT24_TO_STREAM(p, 0x0080de);       // big_sync_delay
                    UINT24_TO_STREAM(p, 0x00cefe);       // transport_latency_big
                    UINT8_TO_STREAM(p, big_params.phy);  // phy
                    UINT8_TO_STREAM(p, 4);               // nse
                    UINT8_TO_STREAM(p, 1);               // bn
                    UINT8_TO_STREAM(p, 0);               // pto
                    UINT8_TO_STREAM(p, 4);               // irc
                    UINT16_TO_STREAM(p, 108);            // max_pdu
                    UINT16_TO_STREAM(p, 6);              // iso_interval

                    UINT8_TO_STREAM(p, big_params.num_bis);
                    static uint8_t conn_hdl = 0x01;
                    for (auto i = 0; i < big_params.num_bis; ++i) {
                      UINT16_TO_STREAM(p, conn_hdl++);
                    }

                    IsoManager::GetInstance()->HandleHciEvent(HCI_BLE_CREATE_BIG_CPL_EVT,
                                                              buf.data(), buf.size());
                  });

  IsoManager::GetInstance()->CreateBig(0x01, kDefaultBigParams);
  ASSERT_EQ(evt.status, 0x01);
  ASSERT_EQ(evt.big_id, 0x01);
  ASSERT_EQ(evt.conn_handles.size(), kDefaultBigParams.num_bis);
}

TEST_F(IsoManagerDeathTest, CreateSameBigTwice) {
  bluetooth::hci::iso_manager::big_create_cmpl_evt evt;
  evt.status = 0x01;
  EXPECT_CALL(*big_callbacks_, OnBigEvent(bluetooth::hci::iso_manager::kIsoEventBigOnCreateCmpl, _))
          .WillOnce([&evt](uint8_t /* type */, void* data) {
            evt = *static_cast<bluetooth::hci::iso_manager::big_create_cmpl_evt*>(data);
            return 0;
          });

  IsoManager::GetInstance()->CreateBig(0x01, kDefaultBigParams);
  ASSERT_EQ(evt.status, HCI_SUCCESS);
  ASSERT_EQ(evt.big_id, 0x01);
  ASSERT_EQ(evt.conn_handles.size(), kDefaultBigParams.num_bis);
}

TEST_F(IsoManagerTest, TerminateBigHciCall) {
  const uint8_t big_id = 0x22;
  const uint8_t reason = 0x16;  // Terminated by local host

  IsoManager::GetInstance()->CreateBig(big_id, kDefaultBigParams);
  EXPECT_CALL(hcic_interface_, TerminateBig(big_id, reason)).Times(1);
  IsoManager::GetInstance()->TerminateBig(big_id, reason);
}

TEST_F(IsoManagerDeathTest, TerminateSameBigTwice) {
  const uint8_t big_id = 0x22;
  const uint8_t reason = 0x16;  // Terminated by local host

  IsoManager::GetInstance()->CreateBig(big_id, kDefaultBigParams);
  EXPECT_CALL(*big_callbacks_,
              OnBigEvent(bluetooth::hci::iso_manager::kIsoEventBigOnTerminateCmpl, _));

  IsoManager::GetInstance()->TerminateBig(big_id, reason);
  ASSERT_EXIT(IsoManager::GetInstance()->TerminateBig(big_id, reason),
              ::testing::KilledBySignal(SIGABRT), "No such big");
}

TEST_F(IsoManagerDeathTest, TerminateBigNoSuchBig) {
  const uint8_t big_id = 0x01;
  const uint8_t reason = 0x16;  // Terminated by local host

  EXPECT_CALL(*big_callbacks_,
              OnBigEvent(bluetooth::hci::iso_manager::kIsoEventBigOnCreateCmpl, _));
  IsoManager::GetInstance()->CreateBig(big_id, kDefaultBigParams);

  ASSERT_EXIT(IsoManager::GetInstance()->TerminateBig(big_id + 1, reason),
              ::testing::KilledBySignal(SIGABRT), "No such big");
}

TEST_F(IsoManagerDeathTest, TerminateBigInvalidResponsePacket) {
  ON_CALL(hcic_interface_, TerminateBig).WillByDefault([](auto /* big_handle */, uint8_t reason) {
    std::vector<uint8_t> buf(1);
    uint8_t* p = buf.data();
    UINT8_TO_STREAM(p, reason);

    IsoManager::GetInstance()->HandleHciEvent(HCI_BLE_TERM_BIG_CPL_EVT, buf.data(), buf.size());
  });

  const uint8_t big_id = 0x22;
  const uint8_t reason = 0x16;  // Terminated by local host

  IsoManager::GetInstance()->CreateBig(big_id, kDefaultBigParams);
  ASSERT_EXIT(IsoManager::GetInstance()->TerminateBig(big_id, reason),
              ::testing::KilledBySignal(SIGABRT), "Invalid packet length");
}

TEST_F(IsoManagerDeathTest, TerminateBigInvalidResponsePacket2) {
  const uint8_t big_id = 0x22;
  const uint8_t reason = 0x16;  // Terminated by local host

  ON_CALL(hcic_interface_, TerminateBig).WillByDefault([](auto /* big_handle */, uint8_t reason) {
    std::vector<uint8_t> buf(3);
    uint8_t* p = buf.data();
    UINT8_TO_STREAM(p, reason);

    IsoManager::GetInstance()->HandleHciEvent(HCI_BLE_TERM_BIG_CPL_EVT, buf.data(), buf.size());
  });

  IsoManager::GetInstance()->CreateBig(big_id, kDefaultBigParams);
  ASSERT_EXIT(IsoManager::GetInstance()->TerminateBig(big_id, reason),
              ::testing::KilledBySignal(SIGABRT), "Invalid packet length");
}

TEST_F(IsoManagerTest, TerminateBigInvalidResponseBigId) {
  const uint8_t big_id = 0x22;
  const uint8_t reason = 0x16;  // Terminated by local host

  ON_CALL(hcic_interface_, TerminateBig).WillByDefault([](auto big_handle, uint8_t reason) {
    std::vector<uint8_t> buf(2);
    uint8_t* p = buf.data();
    UINT8_TO_STREAM(p, reason);
    UINT8_TO_STREAM(p, big_handle + 1);

    IsoManager::GetInstance()->HandleHciEvent(HCI_BLE_TERM_BIG_CPL_EVT, buf.data(), buf.size());
  });

  IsoManager::GetInstance()->CreateBig(big_id, kDefaultBigParams);
  ASSERT_EXIT(IsoManager::GetInstance()->TerminateBig(big_id, reason),
              ::testing::KilledBySignal(SIGABRT), "No such big");
}

TEST_F(IsoManagerTest, TerminateBigValid) {
  const uint8_t big_id = 0x22;
  const uint8_t reason = 0x16;  // Terminated by local host
  bluetooth::hci::iso_manager::big_terminate_cmpl_evt evt;
  ASSERT_EQ(IsIsoActive, false);

  IsoManager::GetInstance()->CreateBig(big_id, kDefaultBigParams);
  ASSERT_EQ(IsIsoActive, true);

  EXPECT_CALL(*big_callbacks_,
              OnBigEvent(bluetooth::hci::iso_manager::kIsoEventBigOnTerminateCmpl, _))
          .WillOnce([&evt](uint8_t /* type */, void* data) {
            evt = *static_cast<bluetooth::hci::iso_manager::big_terminate_cmpl_evt*>(data);
            return 0;
          });

  IsoManager::GetInstance()->TerminateBig(big_id, reason);
  ASSERT_EQ(evt.big_id, big_id);
  ASSERT_EQ(evt.reason, reason);
  ASSERT_EQ(IsIsoActive, false);
}

TEST_F(IsoManagerTest, SetupIsoDataPathValid) {
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);
  IsoManager::GetInstance()->CreateBig(volatile_test_big_params_evt_.big_id, kDefaultBigParams);

  // Establish all CISes before setting up their data paths
  bluetooth::hci::iso_manager::cis_establish_params params;
  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    params.conn_pairs.push_back({handle, 1});
  }
  IsoManager::GetInstance()->EstablishCis(params);

  bluetooth::hci::iso_manager::iso_data_path_params path_params = kDefaultIsoDataPathParams;

  // Setup data paths for all CISes
  path_params.data_path_dir = bluetooth::hci::iso_manager::kIsoDataPathDirectionIn;
  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    EXPECT_CALL(*cig_callbacks_,
                OnSetupIsoDataPath(HCI_SUCCESS, handle, volatile_test_cig_create_cmpl_evt_.cig_id))
            .Times(1)
            .RetiresOnSaturation();

    path_params.data_path_dir = (bluetooth::hci::iso_manager::kIsoDataPathDirectionIn + handle) % 2;

    IsoManager::GetInstance()->SetupIsoDataPath(handle, path_params);
  }

  // Setup data paths for all BISes
  path_params.data_path_dir = bluetooth::hci::iso_manager::kIsoDataPathDirectionOut;
  for (auto& handle : volatile_test_big_params_evt_.conn_handles) {
    std::cerr << "setting up BIS data path on conn_hdl: " << int{handle};
    EXPECT_CALL(*big_callbacks_,
                OnSetupIsoDataPath(HCI_SUCCESS, handle, volatile_test_big_params_evt_.big_id))
            .Times(1)
            .RetiresOnSaturation();

    IsoManager::GetInstance()->SetupIsoDataPath(handle, path_params);
  }
}

TEST_F(IsoManagerTest, SetupIsoDataPathTwice) {
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);

  // Establish CISes
  bluetooth::hci::iso_manager::cis_establish_params params;
  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    params.conn_pairs.push_back({handle, 1});
  }
  IsoManager::GetInstance()->EstablishCis(params);

  // Setup data paths for all CISes twice
  bluetooth::hci::iso_manager::iso_data_path_params path_params = kDefaultIsoDataPathParams;
  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    IsoManager::GetInstance()->SetupIsoDataPath(handle, path_params);
    // Should be possible to reconfigure
    IsoManager::GetInstance()->SetupIsoDataPath(handle, path_params);
  }

  IsoManager::GetInstance()->CreateBig(volatile_test_big_params_evt_.big_id, kDefaultBigParams);
  // Setup data paths for all BISes twice
  for (auto& handle : volatile_test_big_params_evt_.conn_handles) {
    IsoManager::GetInstance()->SetupIsoDataPath(handle, path_params);
    // Should be possible to reconfigure
    IsoManager::GetInstance()->SetupIsoDataPath(handle, path_params);
  }
}

TEST_F(IsoManagerTest, SetupIsoDataPathInvalidStatus) {
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);
  IsoManager::GetInstance()->CreateBig(volatile_test_big_params_evt_.big_id, kDefaultBigParams);

  // Establish all CISes before setting up their data paths
  bluetooth::hci::iso_manager::cis_establish_params params;
  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    params.conn_pairs.push_back({handle, 1});
  }
  IsoManager::GetInstance()->EstablishCis(params);

  bluetooth::hci::iso_manager::iso_data_path_params path_params = kDefaultIsoDataPathParams;

  uint8_t setup_datapath_rsp_status = HCI_SUCCESS;
  ON_CALL(hcic_interface_, SetupIsoDataPath)
          .WillByDefault(
                  [&setup_datapath_rsp_status](uint16_t iso_handle, uint8_t, uint8_t, uint8_t,
                                               uint16_t, uint16_t, uint32_t, std::vector<uint8_t>,
                                               base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
                    std::vector<uint8_t> buf(3);
                    uint8_t* p = buf.data();
                    UINT8_TO_STREAM(p, setup_datapath_rsp_status);
                    UINT16_TO_STREAM(p, iso_handle);

                    std::move(cb).Run(buf.data(), buf.size());
                  });

  // Try to setup data paths for all CISes
  path_params.data_path_dir = bluetooth::hci::iso_manager::kIsoDataPathDirectionIn;
  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    // Mock the response with status != HCI_SUCCESS
    EXPECT_CALL(*cig_callbacks_,
                OnSetupIsoDataPath(0x11, handle, volatile_test_cig_create_cmpl_evt_.cig_id))
            .Times(1)
            .RetiresOnSaturation();
    setup_datapath_rsp_status = 0x11;
    IsoManager::GetInstance()->SetupIsoDataPath(handle, path_params);

    // It should be possible to retry on the same handle after the first
    // failure
    EXPECT_CALL(*cig_callbacks_,
                OnSetupIsoDataPath(HCI_SUCCESS, handle, volatile_test_cig_create_cmpl_evt_.cig_id))
            .Times(1)
            .RetiresOnSaturation();
    setup_datapath_rsp_status = HCI_SUCCESS;
    IsoManager::GetInstance()->SetupIsoDataPath(handle, path_params);
  }

  // Try to setup data paths for all BISes
  path_params.data_path_dir = bluetooth::hci::iso_manager::kIsoDataPathDirectionOut;
  for (auto& handle : volatile_test_big_params_evt_.conn_handles) {
    EXPECT_CALL(*big_callbacks_,
                OnSetupIsoDataPath(0x11, handle, volatile_test_big_params_evt_.big_id))
            .Times(1)
            .RetiresOnSaturation();
    setup_datapath_rsp_status = 0x11;
    IsoManager::GetInstance()->SetupIsoDataPath(handle, path_params);

    EXPECT_CALL(*big_callbacks_,
                OnSetupIsoDataPath(HCI_SUCCESS, handle, volatile_test_big_params_evt_.big_id))
            .Times(1)
            .RetiresOnSaturation();
    setup_datapath_rsp_status = HCI_SUCCESS;
    IsoManager::GetInstance()->SetupIsoDataPath(handle, path_params);
  }
}

TEST_F(IsoManagerTest, SetupIsoDataPathLateArrivingCallback) {
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);
  IsoManager::GetInstance()->CreateBig(volatile_test_big_params_evt_.big_id, kDefaultBigParams);

  // Establish all CISes before setting up their data paths
  bluetooth::hci::iso_manager::cis_establish_params params;
  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    params.conn_pairs.push_back({handle, 1});
  }
  IsoManager::GetInstance()->EstablishCis(params);

  bluetooth::hci::iso_manager::iso_data_path_params path_params = kDefaultIsoDataPathParams;

  // Catch the callback
  base::OnceCallback<void(uint8_t*, uint16_t)> iso_cb;
  ON_CALL(hcic_interface_, SetupIsoDataPath)
          .WillByDefault([&iso_cb](uint16_t /* iso_handle */, uint8_t /* data_path_dir */,
                                   uint8_t /* data_path_id */, uint8_t /* codec_id_format */,
                                   uint16_t /* codec_id_company */, uint16_t /* codec_id_vendor */,
                                   uint32_t /* controller_delay */,
                                   std::vector<uint8_t> /* codec_conf */,
                                   base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
            iso_cb = std::move(cb);
          });
  // Setup and remove data paths for all CISes
  path_params.data_path_dir = bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionInput;
  auto& handle = volatile_test_cig_create_cmpl_evt_.conn_handles[0];
  IsoManager::GetInstance()->SetupIsoDataPath(handle, path_params);

  // Stop the IsoManager before calling the callback
  IsoManager::GetInstance()->Stop();

  // Call the callback and expect no call
  EXPECT_CALL(*cig_callbacks_, OnSetupIsoDataPath(_, handle, _)).Times(0);
  ASSERT_FALSE(iso_cb.is_null());

  std::vector<uint8_t> buf(3);
  uint8_t* p = buf.data();
  UINT8_TO_STREAM(p, HCI_SUCCESS);
  UINT16_TO_STREAM(p, handle);
  std::move(iso_cb).Run(buf.data(), buf.size());
}

TEST_F(IsoManagerTest, RemoveIsoDataPathValid) {
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);
  IsoManager::GetInstance()->CreateBig(volatile_test_big_params_evt_.big_id, kDefaultBigParams);

  // Establish all CISes before setting up their data paths
  bluetooth::hci::iso_manager::cis_establish_params params;
  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    params.conn_pairs.push_back({handle, 1});
  }
  IsoManager::GetInstance()->EstablishCis(params);

  bluetooth::hci::iso_manager::iso_data_path_params path_params = kDefaultIsoDataPathParams;

  // Setup and remove data paths for all CISes
  path_params.data_path_dir = bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionInput;
  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    IsoManager::GetInstance()->SetupIsoDataPath(handle, path_params);

    EXPECT_CALL(*cig_callbacks_,
                OnRemoveIsoDataPath(HCI_SUCCESS, handle, volatile_test_cig_create_cmpl_evt_.cig_id))
            .Times(1)
            .RetiresOnSaturation();
    IsoManager::GetInstance()->RemoveIsoDataPath(handle, path_params.data_path_dir);
  }

  // Setup and remove data paths for all BISes
  path_params.data_path_dir = bluetooth::hci::iso_manager::kIsoDataPathDirectionOut;
  for (auto& handle : volatile_test_big_params_evt_.conn_handles) {
    std::cerr << "setting up BIS data path on conn_hdl: " << int{handle};
    IsoManager::GetInstance()->SetupIsoDataPath(handle, path_params);

    EXPECT_CALL(*big_callbacks_,
                OnRemoveIsoDataPath(HCI_SUCCESS, handle, volatile_test_big_params_evt_.big_id))
            .Times(1)
            .RetiresOnSaturation();
    IsoManager::GetInstance()->RemoveIsoDataPath(handle, path_params.data_path_dir);
  }
}

TEST_F(IsoManagerDeathTest, RemoveIsoDataPathNoSuchPath) {
  // Check on CIS
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);
  uint16_t iso_handle = volatile_test_cig_create_cmpl_evt_.conn_handles[0];
  ASSERT_EXIT(IsoManager::GetInstance()->RemoveIsoDataPath(
                      iso_handle, bluetooth::hci::iso_manager::kIsoDataPathDirectionOut),
              ::testing::KilledBySignal(SIGABRT), "path not set");

  IsoManager::GetInstance()->EstablishCis({.conn_pairs = {{iso_handle, 1}}});
  ASSERT_EXIT(IsoManager::GetInstance()->RemoveIsoDataPath(
                      iso_handle, bluetooth::hci::iso_manager::kIsoDataPathDirectionOut),
              ::testing::KilledBySignal(SIGABRT), "path not set");

  // Check on BIS
  iso_handle = volatile_test_big_params_evt_.conn_handles[0];
  IsoManager::GetInstance()->CreateBig(volatile_test_big_params_evt_.big_id, kDefaultBigParams);
  ASSERT_EXIT(IsoManager::GetInstance()->RemoveIsoDataPath(
                      iso_handle, bluetooth::hci::iso_manager::kIsoDataPathDirectionOut),
              ::testing::KilledBySignal(SIGABRT), "path not set");
}

TEST_F(IsoManagerDeathTest, RemoveIsoDataPathTwice) {
  // Check on CIS
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);
  uint16_t iso_handle = volatile_test_cig_create_cmpl_evt_.conn_handles[0];
  IsoManager::GetInstance()->EstablishCis({.conn_pairs = {{iso_handle, 1}}});
  IsoManager::GetInstance()->SetupIsoDataPath(iso_handle, kDefaultIsoDataPathParams);
  IsoManager::GetInstance()->RemoveIsoDataPath(iso_handle, kDefaultIsoDataPathParams.data_path_dir);
  ASSERT_EXIT(IsoManager::GetInstance()->RemoveIsoDataPath(
                      iso_handle, bluetooth::hci::iso_manager::kIsoDataPathDirectionOut),
              ::testing::KilledBySignal(SIGABRT), "path not set");

  // Check on BIS
  iso_handle = volatile_test_big_params_evt_.conn_handles[0];
  IsoManager::GetInstance()->CreateBig(volatile_test_big_params_evt_.big_id, kDefaultBigParams);
  IsoManager::GetInstance()->SetupIsoDataPath(iso_handle, kDefaultIsoDataPathParams);
  IsoManager::GetInstance()->RemoveIsoDataPath(iso_handle, kDefaultIsoDataPathParams.data_path_dir);
  ASSERT_EXIT(IsoManager::GetInstance()->RemoveIsoDataPath(
                      iso_handle, bluetooth::hci::iso_manager::kIsoDataPathDirectionOut),
              ::testing::KilledBySignal(SIGABRT), "path not set");
}

// Check if HCI status other than HCI_SUCCESS is being propagated to the caller
TEST_F(IsoManagerTest, RemoveIsoDataPathInvalidStatus) {
  // Mock invalid status response
  uint8_t remove_datapath_rsp_status = 0x12;
  ON_CALL(hcic_interface_, RemoveIsoDataPath)
          .WillByDefault(
                  [&remove_datapath_rsp_status](uint16_t iso_handle, uint8_t /* data_path_dir */,
                                                base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
                    std::vector<uint8_t> buf(3);
                    uint8_t* p = buf.data();
                    UINT8_TO_STREAM(p, remove_datapath_rsp_status);
                    UINT16_TO_STREAM(p, iso_handle);

                    std::move(cb).Run(buf.data(), buf.size());
                  });

  // Check on CIS
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);
  uint16_t iso_handle = volatile_test_cig_create_cmpl_evt_.conn_handles[0];
  IsoManager::GetInstance()->EstablishCis({.conn_pairs = {{iso_handle, 1}}});
  IsoManager::GetInstance()->SetupIsoDataPath(iso_handle, kDefaultIsoDataPathParams);

  EXPECT_CALL(*cig_callbacks_, OnRemoveIsoDataPath(remove_datapath_rsp_status, iso_handle,
                                                   volatile_test_cig_create_cmpl_evt_.cig_id))
          .Times(1);
  IsoManager::GetInstance()->RemoveIsoDataPath(iso_handle, kDefaultIsoDataPathParams.data_path_dir);

  // Check on BIS
  iso_handle = volatile_test_big_params_evt_.conn_handles[0];
  IsoManager::GetInstance()->CreateBig(volatile_test_big_params_evt_.big_id, kDefaultBigParams);
  IsoManager::GetInstance()->SetupIsoDataPath(iso_handle, kDefaultIsoDataPathParams);

  EXPECT_CALL(*big_callbacks_, OnRemoveIsoDataPath(remove_datapath_rsp_status, iso_handle,
                                                   volatile_test_big_params_evt_.big_id))
          .Times(1);
  IsoManager::GetInstance()->RemoveIsoDataPath(iso_handle, kDefaultIsoDataPathParams.data_path_dir);
}

TEST_F(IsoManagerTest, RemoveIsoDataPathLateArrivingCallback) {
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);
  IsoManager::GetInstance()->CreateBig(volatile_test_big_params_evt_.big_id, kDefaultBigParams);

  // Establish all CISes before setting up their data paths
  bluetooth::hci::iso_manager::cis_establish_params params;
  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    params.conn_pairs.push_back({handle, 1});
  }
  IsoManager::GetInstance()->EstablishCis(params);

  bluetooth::hci::iso_manager::iso_data_path_params path_params = kDefaultIsoDataPathParams;

  // Setup and remove data paths for all CISes
  path_params.data_path_dir = bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionInput;
  auto& handle = volatile_test_cig_create_cmpl_evt_.conn_handles[0];
  IsoManager::GetInstance()->SetupIsoDataPath(handle, path_params);

  // Catch the callback
  base::OnceCallback<void(uint8_t*, uint16_t)> iso_cb;
  ON_CALL(hcic_interface_, RemoveIsoDataPath)
          .WillByDefault([&iso_cb](uint16_t /* iso_handle */, uint8_t /* data_path_dir */,
                                   base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
            iso_cb = std::move(cb);
          });
  IsoManager::GetInstance()->RemoveIsoDataPath(handle, path_params.data_path_dir);

  // Stop the IsoManager before calling the callback
  IsoManager::GetInstance()->Stop();

  // Call the callback and expect no call
  EXPECT_CALL(*cig_callbacks_,
              OnRemoveIsoDataPath(HCI_SUCCESS, handle, volatile_test_cig_create_cmpl_evt_.cig_id))
          .Times(0);
  ASSERT_FALSE(iso_cb.is_null());

  std::vector<uint8_t> buf(3);
  uint8_t* p = buf.data();
  UINT8_TO_STREAM(p, HCI_SUCCESS);
  UINT16_TO_STREAM(p, handle);
  std::move(iso_cb).Run(buf.data(), buf.size());
}

TEST_F(IsoManagerTest, SendIsoDataWithNoCigConnected) {
  std::vector<uint8_t> data_vec(108, 0);
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);

  auto handle = volatile_test_cig_create_cmpl_evt_.conn_handles[0];
  IsoManager::GetInstance()->SendIsoData(handle, data_vec.data(), data_vec.size());
  EXPECT_CALL(iso_interface_, HciSend).Times(0);
}

TEST_F(IsoManagerTest, SendIsoDataCigValid) {
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);

  bluetooth::hci::iso_manager::cis_establish_params params;
  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    params.conn_pairs.push_back({handle, 1});
  }
  IsoManager::GetInstance()->EstablishCis(params);

  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    bluetooth::hci::iso_manager::iso_data_path_params path_params = kDefaultIsoDataPathParams;
    path_params.data_path_dir = bluetooth::hci::iso_manager::kIsoDataPathDirectionOut;
    IsoManager::GetInstance()->SetupIsoDataPath(handle, path_params);

    for (uint8_t num_pkts = 2; num_pkts != 0; num_pkts--) {
      constexpr uint8_t data_len = 108;

      EXPECT_CALL(iso_interface_, HciSend)
              .WillOnce([handle, data_len](BT_HDR* p_msg) {
                uint8_t* p = p_msg->data;
                uint16_t msg_handle;
                uint16_t iso_load_len;

                ASSERT_NE(p_msg, nullptr);
                ASSERT_EQ(p_msg->len,
                          data_len + ((p_msg->layer_specific & BT_ISO_HDR_CONTAINS_TS) ? 12 : 8));

                // Verify packet internals
                STREAM_TO_UINT16(msg_handle, p);
                ASSERT_EQ(msg_handle, handle);

                STREAM_TO_UINT16(iso_load_len, p);
                ASSERT_EQ(iso_load_len,
                          data_len + ((p_msg->layer_specific & BT_ISO_HDR_CONTAINS_TS) ? 8 : 4));

                if (p_msg->layer_specific & BT_ISO_HDR_CONTAINS_TS) {
                  STREAM_SKIP_UINT16(p);  // skip ts LSB halfword
                  STREAM_SKIP_UINT16(p);  // skip ts MSB halfword
                }
                STREAM_SKIP_UINT16(p);  // skip seq_nb

                uint16_t msg_data_len;
                STREAM_TO_UINT16(msg_data_len, p);
                ASSERT_EQ(msg_data_len, data_len);
              })
              .RetiresOnSaturation();

      std::vector<uint8_t> data_vec(data_len, 0);
      IsoManager::GetInstance()->SendIsoData(handle, data_vec.data(), data_vec.size());
    }
  }
}

TEST_F(IsoManagerTest, SendReceiveIsoDataSequenceNumberCheck) {
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);

  bluetooth::hci::iso_manager::cis_establish_params params;
  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    params.conn_pairs.push_back({handle, 1});
  }
  IsoManager::GetInstance()->EstablishCis(params);

  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    bluetooth::hci::iso_manager::iso_data_path_params path_params = kDefaultIsoDataPathParams;
    path_params.data_path_dir = bluetooth::hci::iso_manager::kIsoDataPathDirectionOut;
    IsoManager::GetInstance()->SetupIsoDataPath(handle, path_params);

    constexpr uint8_t data_len = 108;
    uint16_t seq_num = 0xFFFF;

    EXPECT_CALL(iso_interface_, HciSend)
            .WillRepeatedly([handle, data_len, &seq_num](BT_HDR* p_msg) {
              uint8_t* p = p_msg->data;
              uint16_t msg_handle;
              uint16_t iso_load_len;

              ASSERT_NE(p_msg, nullptr);
              ASSERT_EQ(p_msg->len,
                        data_len + ((p_msg->layer_specific & BT_ISO_HDR_CONTAINS_TS) ? 12 : 8));

              // Verify packet internals
              STREAM_TO_UINT16(msg_handle, p);
              ASSERT_EQ(msg_handle, handle);

              STREAM_TO_UINT16(iso_load_len, p);
              ASSERT_EQ(iso_load_len,
                        data_len + ((p_msg->layer_specific & BT_ISO_HDR_CONTAINS_TS) ? 8 : 4));

              if (p_msg->layer_specific & BT_ISO_HDR_CONTAINS_TS) {
                STREAM_SKIP_UINT16(p);  // skip ts LSB halfword
                STREAM_SKIP_UINT16(p);  // skip ts MSB halfword
              }
              // store the seq_nb
              STREAM_TO_UINT16(seq_num, p);

              uint16_t msg_data_len;
              STREAM_TO_UINT16(msg_data_len, p);
              ASSERT_EQ(msg_data_len, data_len);
            })
            .RetiresOnSaturation();

    // Send Iso data and verify the sequence number
    std::vector<uint8_t> data_vec(data_len, 0);
    IsoManager::GetInstance()->SendIsoData(handle, data_vec.data(), data_vec.size());
    IsoManager::GetInstance()->SendIsoData(handle, data_vec.data(), data_vec.size());
    ASSERT_NE(0xFFFF, seq_num);

    // Check the receiving iso packet
    // EXPECT_CALL(*cig_callbacks_, OnCisEvent).Times(1);
    EXPECT_CALL(*cig_callbacks_,
                OnCisEvent(bluetooth::hci::iso_manager::kIsoEventCisDataAvailable, _))
            .WillOnce([](uint8_t /*evt_code*/, void* event) {
              bluetooth::hci::iso_manager::cis_data_evt* cis_data_evt =
                      static_cast<bluetooth::hci::iso_manager::cis_data_evt*>(event);
              // Make sure no event lost is reported due to seq_nb being shared between two
              // directions
              ASSERT_EQ(cis_data_evt->evt_lost, 0);
            });

    std::vector<uint8_t> dummy_msg(18);
    uint8_t* p = dummy_msg.data();
    UINT16_TO_STREAM(p, BT_EVT_TO_BTU_HCI_ISO);
    UINT16_TO_STREAM(p, 10);  // .len
    UINT16_TO_STREAM(p, 0);   // .offset
    UINT16_TO_STREAM(p, 0);   // .layer_specific
    UINT16_TO_STREAM(p, handle);
    IsoManager::GetInstance()->HandleIsoData(dummy_msg.data());
  }
}

TEST_F(IsoManagerTest, SendIsoDataBigValid) {
  IsoManager::GetInstance()->CreateBig(volatile_test_big_params_evt_.big_id, kDefaultBigParams);

  for (auto& handle : volatile_test_big_params_evt_.conn_handles) {
    IsoManager::GetInstance()->SetupIsoDataPath(handle, kDefaultIsoDataPathParams);
    for (uint8_t num_pkts = 2; num_pkts != 0; num_pkts--) {
      constexpr uint8_t data_len = 108;

      EXPECT_CALL(iso_interface_, HciSend)
              .WillOnce([handle, data_len](BT_HDR* p_msg) {
                uint8_t* p = p_msg->data;
                uint16_t msg_handle;
                uint16_t iso_load_len;

                ASSERT_NE(p_msg, nullptr);
                ASSERT_EQ(p_msg->len,
                          data_len + ((p_msg->layer_specific & BT_ISO_HDR_CONTAINS_TS) ? 12 : 8));

                // Verify packet internals
                STREAM_TO_UINT16(msg_handle, p);
                ASSERT_EQ(msg_handle, handle);

                STREAM_TO_UINT16(iso_load_len, p);
                ASSERT_EQ(iso_load_len,
                          data_len + ((p_msg->layer_specific & BT_ISO_HDR_CONTAINS_TS) ? 8 : 4));

                uint16_t msg_data_len;
                uint16_t msg_dummy;
                if (p_msg->layer_specific & BT_ISO_HDR_CONTAINS_TS) {
                  STREAM_TO_UINT16(msg_dummy, p);  // skip ts LSB halfword
                  STREAM_TO_UINT16(msg_dummy, p);  // skip ts MSB halfword
                }
                STREAM_TO_UINT16(msg_dummy, p);  // skip seq_nb

                STREAM_TO_UINT16(msg_data_len, p);
                ASSERT_EQ(msg_data_len, data_len);
              })
              .RetiresOnSaturation();

      std::vector<uint8_t> data_vec(data_len, 0);
      IsoManager::GetInstance()->SendIsoData(handle, data_vec.data(), data_vec.size());
    }
  }
}

TEST_F(IsoManagerTest, SendIsoDataNoCredits) {
  uint8_t num_buffers = controller_.GetControllerIsoBufferSize().total_num_le_packets_;
  std::vector<uint8_t> data_vec(108, 0);

  // Check on CIG
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);

  bluetooth::hci::iso_manager::cis_establish_params params;
  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    params.conn_pairs.push_back({handle, 1});
  }
  IsoManager::GetInstance()->EstablishCis(params);

  IsoManager::GetInstance()->SetupIsoDataPath(volatile_test_cig_create_cmpl_evt_.conn_handles[0],
                                              kDefaultIsoDataPathParams);

  /* Try sending twice as much data as we can ignoring the credit limits and
   * expect the redundant packets to be ignored and not propagated down to the
   * HCI.
   */
  EXPECT_CALL(iso_interface_, HciSend).Times(num_buffers).RetiresOnSaturation();
  for (uint8_t i = 0; i < (2 * num_buffers); i++) {
    IsoManager::GetInstance()->SendIsoData(volatile_test_cig_create_cmpl_evt_.conn_handles[0],
                                           data_vec.data(), data_vec.size());
  }

  // Return all credits for this one handle
  IsoManager::GetInstance()->HandleNumComplDataPkts(
          volatile_test_cig_create_cmpl_evt_.conn_handles[0], num_buffers);

  // Check on BIG
  IsoManager::GetInstance()->CreateBig(volatile_test_big_params_evt_.big_id, kDefaultBigParams);
  IsoManager::GetInstance()->SetupIsoDataPath(volatile_test_big_params_evt_.conn_handles[0],
                                              kDefaultIsoDataPathParams);

  /* Try sending twice as much data as we can ignoring the credit limits and
   * expect the redundant packets to be ignored and not propagated down to the
   * HCI.
   */
  EXPECT_CALL(iso_interface_, HciSend).Times(num_buffers);
  for (uint8_t i = 0; i < (2 * num_buffers); i++) {
    IsoManager::GetInstance()->SendIsoData(volatile_test_big_params_evt_.conn_handles[0],
                                           data_vec.data(), data_vec.size());
  }
}

TEST_F(IsoManagerTest, SendIsoDataCreditsReturned) {
  uint8_t num_buffers = controller_.GetControllerIsoBufferSize().total_num_le_packets_;
  std::vector<uint8_t> data_vec(108, 0);

  // Check on CIG
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);

  bluetooth::hci::iso_manager::cis_establish_params params;
  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    params.conn_pairs.push_back({handle, 1});
  }
  IsoManager::GetInstance()->EstablishCis(params);

  IsoManager::GetInstance()->SetupIsoDataPath(volatile_test_cig_create_cmpl_evt_.conn_handles[0],
                                              kDefaultIsoDataPathParams);

  /* Try sending twice as much data as we can, ignoring the credits limit and
   * expect the redundant packets to be ignored and not propagated down to the
   * HCI.
   */
  EXPECT_CALL(iso_interface_, HciSend).Times(num_buffers).RetiresOnSaturation();
  for (uint8_t i = 0; i < (2 * num_buffers); i++) {
    IsoManager::GetInstance()->SendIsoData(volatile_test_cig_create_cmpl_evt_.conn_handles[0],
                                           data_vec.data(), data_vec.size());
  }

  // Return all credits for this one handle
  IsoManager::GetInstance()->HandleNumComplDataPkts(
          volatile_test_cig_create_cmpl_evt_.conn_handles[0], num_buffers);

  // Expect some more events go down the HCI
  EXPECT_CALL(iso_interface_, HciSend).Times(num_buffers).RetiresOnSaturation();
  for (uint8_t i = 0; i < (2 * num_buffers); i++) {
    IsoManager::GetInstance()->SendIsoData(volatile_test_cig_create_cmpl_evt_.conn_handles[0],
                                           data_vec.data(), data_vec.size());
  }

  // Return all credits for this one handle
  IsoManager::GetInstance()->HandleNumComplDataPkts(
          volatile_test_cig_create_cmpl_evt_.conn_handles[0], num_buffers);

  // Check on BIG
  IsoManager::GetInstance()->CreateBig(volatile_test_big_params_evt_.big_id, kDefaultBigParams);
  IsoManager::GetInstance()->SetupIsoDataPath(volatile_test_big_params_evt_.conn_handles[0],
                                              kDefaultIsoDataPathParams);

  /* Try sending twice as much data as we can, ignoring the credits limit and
   * expect the redundant packets to be ignored and not propagated down to the
   * HCI.
   */
  EXPECT_CALL(iso_interface_, HciSend).Times(num_buffers).RetiresOnSaturation();
  for (uint8_t i = 0; i < (2 * num_buffers); i++) {
    IsoManager::GetInstance()->SendIsoData(volatile_test_big_params_evt_.conn_handles[0],
                                           data_vec.data(), data_vec.size());
  }

  // Return all credits for this one handle
  IsoManager::GetInstance()->HandleNumComplDataPkts(volatile_test_big_params_evt_.conn_handles[0],
                                                    num_buffers);

  // Expect some more events go down the HCI
  EXPECT_CALL(iso_interface_, HciSend).Times(num_buffers).RetiresOnSaturation();
  for (uint8_t i = 0; i < (2 * num_buffers); i++) {
    IsoManager::GetInstance()->SendIsoData(volatile_test_big_params_evt_.conn_handles[0],
                                           data_vec.data(), data_vec.size());
  }
}

TEST_F(IsoManagerTest, SendIsoDataCreditsReturnedByDisconnection) {
  uint8_t num_buffers = controller_.GetControllerIsoBufferSize().total_num_le_packets_;
  std::vector<uint8_t> data_vec(108, 0);

  // Check on CIG
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);

  bluetooth::hci::iso_manager::cis_establish_params params;
  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    params.conn_pairs.push_back({handle, 1});
  }
  IsoManager::GetInstance()->EstablishCis(params);

  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    IsoManager::GetInstance()->SetupIsoDataPath(handle, kDefaultIsoDataPathParams);
  }

  /* Sending lot of ISO data to first ISO and getting all the credits */
  EXPECT_CALL(iso_interface_, HciSend).Times(num_buffers).RetiresOnSaturation();
  for (uint8_t i = 0; i < num_buffers; i++) {
    IsoManager::GetInstance()->SendIsoData(volatile_test_cig_create_cmpl_evt_.conn_handles[0],
                                           data_vec.data(), data_vec.size());
  }

  /* Return all credits by disconnecting CIS */
  IsoManager::GetInstance()->HandleDisconnect(volatile_test_cig_create_cmpl_evt_.conn_handles[0],
                                              16);

  /* Try to send ISO data on the second ISO. Expect credits being available.*/
  EXPECT_CALL(iso_interface_, HciSend).Times(num_buffers).RetiresOnSaturation();
  for (uint8_t i = 0; i < num_buffers; i++) {
    IsoManager::GetInstance()->SendIsoData(volatile_test_cig_create_cmpl_evt_.conn_handles[1],
                                           data_vec.data(), data_vec.size());
  }
}

TEST_F(IsoManagerDeathTest, SendIsoDataWithNoDataPath) {
  std::vector<uint8_t> data_vec(108, 0);

  // Check on CIG
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);

  bluetooth::hci::iso_manager::cis_establish_params params;
  for (auto& conn_handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    params.conn_pairs.push_back({conn_handle, 1});
  }
  IsoManager::GetInstance()->EstablishCis(params);

  EXPECT_CALL(iso_interface_, HciSend).Times(0);
  IsoManager::GetInstance()->SendIsoData(volatile_test_cig_create_cmpl_evt_.conn_handles[0],
                                         data_vec.data(), data_vec.size());

  // Check on BIG
  IsoManager::GetInstance()->CreateBig(volatile_test_big_params_evt_.big_id, kDefaultBigParams);

  EXPECT_CALL(iso_interface_, HciSend).Times(0);
  IsoManager::GetInstance()->SendIsoData(volatile_test_big_params_evt_.conn_handles[0],
                                         data_vec.data(), data_vec.size());
}

TEST_F(IsoManagerDeathTest, SendIsoDataWithNoCigBigHandle) {
  std::vector<uint8_t> data_vec(108, 0);
  ASSERT_EXIT(IsoManager::GetInstance()->SendIsoData(134, data_vec.data(), data_vec.size()),
              ::testing::KilledBySignal(SIGABRT), "No such iso");
}

TEST_F(IsoManagerTest, HandleDisconnectNoSuchHandle) {
  // Don't expect any callbacks when connection handle is not for ISO.
  EXPECT_CALL(*cig_callbacks_, OnCigEvent).Times(0);
  EXPECT_CALL(*cig_callbacks_, OnCisEvent).Times(0);
  EXPECT_CALL(*big_callbacks_, OnBigEvent).Times(0);

  IsoManager::GetInstance()->HandleDisconnect(123, 16);
}

TEST_F(IsoManagerTest, HandleDisconnectValidCig) {
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);

  auto handle = volatile_test_cig_create_cmpl_evt_.conn_handles[0];
  IsoManager::GetInstance()->EstablishCis({{{handle, 1}}});

  EXPECT_CALL(*big_callbacks_, OnBigEvent).Times(0);
  EXPECT_CALL(*cig_callbacks_, OnCigEvent).Times(0);
  EXPECT_CALL(*cig_callbacks_, OnCisEvent).Times(0);

  // Expect disconnect event exactly once
  EXPECT_CALL(*cig_callbacks_, OnCisEvent).WillOnce([this, handle](uint8_t event_code, void* data) {
    ASSERT_EQ(event_code, bluetooth::hci::iso_manager::kIsoEventCisDisconnected);
    auto* event = static_cast<bluetooth::hci::iso_manager::cis_disconnected_evt*>(data);
    ASSERT_EQ(event->reason, 16);
    ASSERT_EQ(event->cig_id, volatile_test_cig_create_cmpl_evt_.cig_id);
    ASSERT_EQ(event->cis_conn_hdl, handle);
  });

  IsoManager::GetInstance()->HandleDisconnect(handle, 16);
}

TEST_F(IsoManagerTest, HandleDisconnectDisconnectedCig) {
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);

  auto handle = volatile_test_cig_create_cmpl_evt_.conn_handles[0];
  IsoManager::GetInstance()->EstablishCis({{{handle, 1}}});

  EXPECT_CALL(*big_callbacks_, OnBigEvent).Times(0);
  EXPECT_CALL(*cig_callbacks_, OnCigEvent).Times(0);
  EXPECT_CALL(*cig_callbacks_, OnCisEvent).Times(0);

  // Expect disconnect event exactly once
  EXPECT_CALL(*cig_callbacks_, OnCisEvent(bluetooth::hci::iso_manager::kIsoEventCisDisconnected, _))
          .Times(1)
          .RetiresOnSaturation();
  IsoManager::GetInstance()->HandleDisconnect(handle, 16);

  // This one was once connected - expect no events
  IsoManager::GetInstance()->HandleDisconnect(handle, 16);

  // This one was never connected - expect no events
  handle = volatile_test_cig_create_cmpl_evt_.conn_handles[1];
  IsoManager::GetInstance()->HandleDisconnect(handle, 16);
}

TEST_F(IsoManagerTest, HandleDisconnectLateArrivingCallback) {
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);

  auto handle = volatile_test_cig_create_cmpl_evt_.conn_handles[0];
  IsoManager::GetInstance()->EstablishCis({{{handle, 1}}});

  EXPECT_CALL(*big_callbacks_, OnBigEvent).Times(0);
  EXPECT_CALL(*cig_callbacks_, OnCigEvent).Times(0);
  EXPECT_CALL(*cig_callbacks_, OnCisEvent).Times(0);

  // Expect disconnect event exactly once
  EXPECT_CALL(*cig_callbacks_, OnCisEvent(bluetooth::hci::iso_manager::kIsoEventCisDisconnected, _))
          .Times(0);

  // Expect no callback on late arriving event
  IsoManager::GetInstance()->Stop();
  IsoManager::GetInstance()->HandleDisconnect(handle, 16);
}

TEST_F(IsoManagerTest, HandleIsoData) {
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);

  auto handle = volatile_test_cig_create_cmpl_evt_.conn_handles[0];
  IsoManager::GetInstance()->EstablishCis({{{handle, 1}}});

  EXPECT_CALL(*cig_callbacks_,
              OnCisEvent(bluetooth::hci::iso_manager::kIsoEventCisDataAvailable, _))
          .Times(1);

  std::vector<uint8_t> dummy_msg(18);
  uint8_t* p = dummy_msg.data();
  UINT16_TO_STREAM(p, BT_EVT_TO_BTU_HCI_ISO);
  UINT16_TO_STREAM(p, 10);  // .len
  UINT16_TO_STREAM(p, 0);   // .offset
  UINT16_TO_STREAM(p, 0);   // .layer_specific
  UINT16_TO_STREAM(p, handle);
  IsoManager::GetInstance()->HandleIsoData(dummy_msg.data());
}

/* This test case simulates HCI thread scheduling events on the main thread,
 * without knowing the we are already shutting down the stack and Iso Manager
 * is already stopped.
 */
TEST_F(IsoManagerDeathTestNoCleanup, HandleLateArivingEventHandleIsoData) {
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);

  auto handle = volatile_test_cig_create_cmpl_evt_.conn_handles[0];
  IsoManager::GetInstance()->EstablishCis({{{handle, 1}}});

  // Stop iso manager before trying to call the HCI callbacks
  IsoManager::GetInstance()->Stop();

  EXPECT_CALL(*cig_callbacks_,
              OnCisEvent(bluetooth::hci::iso_manager::kIsoEventCisDataAvailable, _))
          .Times(0);

  // Expect no assert on this call - should be gracefully ignored
  std::vector<uint8_t> dummy_msg(18);
  uint8_t* p = dummy_msg.data();
  UINT16_TO_STREAM(p, BT_EVT_TO_BTU_HCI_ISO);
  UINT16_TO_STREAM(p, 10);  // .len
  UINT16_TO_STREAM(p, 0);   // .offset
  UINT16_TO_STREAM(p, 0);   // .layer_specific
  UINT16_TO_STREAM(p, handle);
  IsoManager::GetInstance()->HandleIsoData(dummy_msg.data());
}

/* This test case simulates HCI thread scheduling events on the main thread,
 * without knowing the we are already shutting down the stack and Iso Manager
 * is already stopped.
 */
TEST_F(IsoManagerDeathTestNoCleanup, HandleLateArivingEventHandleDisconnect) {
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);

  auto handle = volatile_test_cig_create_cmpl_evt_.conn_handles[0];
  IsoManager::GetInstance()->EstablishCis({{{handle, 1}}});

  // Stop iso manager before trying to call the HCI callbacks
  IsoManager::GetInstance()->Stop();

  // Expect no event when callback is being called on a stopped iso manager
  EXPECT_CALL(*cig_callbacks_, OnCisEvent).Times(0);
  // Expect no assert on this call - should be gracefully ignored
  IsoManager::GetInstance()->HandleDisconnect(handle, 16);
}

/* This test case simulates HCI thread scheduling events on the main thread,
 * without knowing the we are already shutting down the stack and Iso Manager
 * is already stopped.
 */
TEST_F(IsoManagerDeathTestNoCleanup, HandleLateArivingEventHandleNumComplDataPkts) {
  uint8_t num_buffers = controller_.GetControllerIsoBufferSize().total_num_le_packets_;

  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);

  auto handle = volatile_test_cig_create_cmpl_evt_.conn_handles[0];
  IsoManager::GetInstance()->EstablishCis({{{handle, 1}}});

  // Stop iso manager before trying to call the HCI callbacks
  IsoManager::GetInstance()->Stop();

  // Expect no assert on this call - should be gracefully ignored
  IsoManager::GetInstance()->HandleNumComplDataPkts(handle, num_buffers);
}

/* This test case simulates HCI thread scheduling events on the main thread,
 * without knowing the we are already shutting down the stack and Iso Manager
 * is already stopped.
 */
TEST_F(IsoManagerDeathTestNoCleanup, HandleLateArivingEventHandleHciEvent) {
  const uint8_t big_id = 0x22;

  IsoManager::GetInstance()->CreateBig(big_id, kDefaultBigParams);

  // Stop iso manager before trying to call the HCI callbacks
  IsoManager::GetInstance()->Stop();
  EXPECT_CALL(*big_callbacks_,
              OnBigEvent(bluetooth::hci::iso_manager::kIsoEventBigOnTerminateCmpl, _))
          .Times(0);

  // Expect no assert on this call - should be gracefully ignored
  std::vector<uint8_t> buf(2);
  uint8_t* p = buf.data();
  UINT8_TO_STREAM(p, big_id);
  UINT8_TO_STREAM(p, 16);  // Terminated by local host
  IsoManager::GetInstance()->HandleHciEvent(HCI_BLE_TERM_BIG_CPL_EVT, buf.data(), buf.size());
}

/* This test makes sure we do not crash when calling into a non-started Iso Manager
 */
TEST_F(IsoManagerDeathTestNoCleanup, HandleApiCallsWhenStopped) {
  IsoManager::GetInstance()->Stop();
  IsoManager::GetInstance()->RegisterCigCallbacks(cig_callbacks_.get());
  IsoManager::GetInstance()->RegisterBigCallbacks(big_callbacks_.get());
  IsoManager::GetInstance()->RegisterOnIsoTrafficActiveCallback(iso_active_callback);

  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);
  IsoManager::GetInstance()->ReconfigureCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                            kDefaultCigParams);

  bluetooth::hci::iso_manager::cis_establish_params params;
  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    params.conn_pairs.push_back({handle, 1});
  }
  IsoManager::GetInstance()->EstablishCis(params);

  bluetooth::hci::iso_manager::iso_data_path_params path_params = kDefaultIsoDataPathParams;
  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    path_params.data_path_dir = bluetooth::hci::iso_manager::kIsoDataPathDirectionIn;
    IsoManager::GetInstance()->SetupIsoDataPath(handle, path_params);

    path_params.data_path_dir = bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionInput;
    IsoManager::GetInstance()->RemoveIsoDataPath(handle, path_params.data_path_dir);
  }

  auto handle = volatile_test_cig_create_cmpl_evt_.conn_handles[0];
  IsoManager::GetInstance()->ReadIsoLinkQuality(handle);

  std::vector<uint8_t> data_vec(108, 0);
  IsoManager::GetInstance()->SendIsoData(handle, data_vec.data(), data_vec.size());
  IsoManager::GetInstance()->SendIsoData(handle, data_vec.data(), data_vec.size());

  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    IsoManager::GetInstance()->IsoManager::GetInstance()->DisconnectCis(handle, 0x16);
  }

  IsoManager::GetInstance()->RemoveCig(volatile_test_cig_create_cmpl_evt_.cig_id);
  (void)IsoManager::GetInstance()->GetNumberOfActiveIso();

  IsoManager::GetInstance()->CreateBig(volatile_test_big_params_evt_.big_id, kDefaultBigParams);
  IsoManager::GetInstance()->TerminateBig(volatile_test_big_params_evt_.big_id, 0x16);
}

TEST_F(IsoManagerTest, HandleIsoDataSameSeqNb) {
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);

  auto handle = volatile_test_cig_create_cmpl_evt_.conn_handles[0];
  IsoManager::GetInstance()->EstablishCis({{{handle, 1}}});

  EXPECT_CALL(*cig_callbacks_,
              OnCisEvent(bluetooth::hci::iso_manager::kIsoEventCisDataAvailable, _))
          .Times(2);

  std::vector<uint8_t> dummy_msg(18);
  uint8_t* p = dummy_msg.data();
  UINT16_TO_STREAM(p, BT_EVT_TO_BTU_HCI_ISO);
  UINT16_TO_STREAM(p, 10);  // .len
  UINT16_TO_STREAM(p, 0);   // .offset
  UINT16_TO_STREAM(p, 0);   // .layer_specific
  UINT16_TO_STREAM(p, handle);

  IsoManager::GetInstance()->HandleIsoData(dummy_msg.data());
  IsoManager::GetInstance()->HandleIsoData(dummy_msg.data());
}

TEST_F(IsoManagerTest, ReadIsoLinkQualityLateArrivingCallback) {
  IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id,
                                       kDefaultCigParams);

  EXPECT_CALL(*cig_callbacks_,
              OnCisEvent(bluetooth::hci::iso_manager::kIsoEventCisEstablishCmpl, _))
          .Times(kDefaultCigParams.cis_cfgs.size())
          .WillRepeatedly([this](uint8_t /* type */, void* data) {
            bluetooth::hci::iso_manager::cis_establish_cmpl_evt* evt =
                    static_cast<bluetooth::hci::iso_manager::cis_establish_cmpl_evt*>(data);

            ASSERT_EQ(evt->status, HCI_SUCCESS);
            ASSERT_TRUE(std::find(volatile_test_cig_create_cmpl_evt_.conn_handles.begin(),
                                  volatile_test_cig_create_cmpl_evt_.conn_handles.end(),
                                  evt->cis_conn_hdl) !=
                        volatile_test_cig_create_cmpl_evt_.conn_handles.end());
          });

  // Establish all CISes
  bluetooth::hci::iso_manager::cis_establish_params params;
  for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
    params.conn_pairs.push_back({handle, 1});
  }
  IsoManager::GetInstance()->EstablishCis(params);

  // Catch the callback
  base::OnceCallback<void(uint8_t*, uint16_t)> iso_cb;
  ON_CALL(hcic_interface_, ReadIsoLinkQuality)
          .WillByDefault([&iso_cb](uint16_t /* iso_handle */,
                                   base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
            iso_cb = std::move(cb);
          });
  auto handle = volatile_test_cig_create_cmpl_evt_.conn_handles[0];
  IsoManager::GetInstance()->ReadIsoLinkQuality(handle);

  // Stop the IsoManager before calling the callback
  IsoManager::GetInstance()->Stop();

  // Call the callback and expect no call
  EXPECT_CALL(*cig_callbacks_, OnIsoLinkQualityRead(handle, _, _, _, _, _, _, _, _)).Times(0);
  ASSERT_FALSE(iso_cb.is_null());

  std::vector<uint8_t> buf(31);
  uint8_t* p = buf.data();
  UINT8_TO_STREAM(p, HCI_SUCCESS);
  UINT16_TO_STREAM(p, handle);
  UINT32_TO_STREAM(p, 0);
  UINT32_TO_STREAM(p, 0);
  UINT32_TO_STREAM(p, 0);
  UINT32_TO_STREAM(p, 0);
  UINT32_TO_STREAM(p, 0);
  UINT32_TO_STREAM(p, 0);
  UINT32_TO_STREAM(p, 0);
  std::move(iso_cb).Run(buf.data(), buf.size());
}
