// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "generic_attribute_service.h"

#include <zircon/assert.h>

#include "gtest/gtest.h"
#include "src/connectivity/bluetooth/core/bt-host/gatt/gatt_defs.h"

namespace bt {
namespace gatt {
namespace {

void NopReadHandler(IdType, IdType, uint16_t, const ReadResponder&) {}
void NopWriteHandler(IdType, IdType, uint16_t, const ByteBuffer&,
                     const WriteResponder&) {}
void NopCCCallback(IdType, IdType, PeerId, bool notify, bool indicate) {}
void NopSendIndication(PeerId, att::Handle, const ByteBuffer&) {}

// Handles for the third attribute (Service Changed characteristic) and fourth
// attribute (corresponding client config).
constexpr att::Handle kChrcHandle = 0x0003;
constexpr att::Handle kCCCHandle = 0x0004;
constexpr PeerId kTestPeerId(1);
constexpr uint16_t kEnableInd = 0x0002;

class GATT_GenericAttributeServiceTest : public ::testing::Test {
 protected:
  bool WriteServiceChangedCCC(PeerId peer_id, uint16_t ccc_value,
                              att::ErrorCode* out_ecode) {
    ZX_DEBUG_ASSERT(out_ecode);

    auto* attr = mgr.database()->FindAttribute(kCCCHandle);
    ZX_DEBUG_ASSERT(attr);
    auto result_cb = [&out_ecode](auto cb_code) { *out_ecode = cb_code; };
    uint16_t value = htole16(ccc_value);
    return attr->WriteAsync(peer_id, 0u, BufferView(&value, sizeof(value)),
                            result_cb);
  }

  LocalServiceManager mgr;
};

// Test registration and unregistration of the local GATT service itself.
TEST_F(GATT_GenericAttributeServiceTest, RegisterUnregister) {
  {
    GenericAttributeService gatt_service(&mgr, NopSendIndication);

    // Check that the local attribute database has a grouping for the GATT GATT
    // service with four attributes.
    auto iter = mgr.database()->groupings().begin();
    EXPECT_TRUE(iter->complete());
    EXPECT_EQ(4u, iter->attributes().size());
    EXPECT_TRUE(iter->active());
    EXPECT_EQ(0x0001, iter->start_handle());
    EXPECT_EQ(0x0004, iter->end_handle());
    EXPECT_EQ(types::kPrimaryService, iter->group_type());

    auto const* ccc_attr = mgr.database()->FindAttribute(kCCCHandle);
    ASSERT_TRUE(ccc_attr != nullptr);
    EXPECT_EQ(types::kClientCharacteristicConfig, ccc_attr->type());
  }

  // The service should now be unregistered, so no characeteristic attributes
  // should be active.
  auto const* chrc_attr = mgr.database()->FindAttribute(kChrcHandle);
  ASSERT_TRUE(chrc_attr == nullptr);
}

// Tests that registering the GATT service, enabling indication on its Service
// Changed characteristic, then registering a different service invokes the
// callback to send an indication to the "client."
TEST_F(GATT_GenericAttributeServiceTest, IndicateOnRegister) {
  int callback_count = 0;
  auto send_indication = [&](PeerId peer_id, att::Handle handle,
                             const ByteBuffer& value) {
    EXPECT_EQ(kTestPeerId, peer_id);
    EXPECT_EQ(kChrcHandle, handle);
    ASSERT_EQ(4u, value.size());

    // The second service following the four-attribute GATT service should span
    // the subsequent three handles.
    EXPECT_EQ(0x05, value[0]);
    EXPECT_EQ(0x00, value[1]);
    EXPECT_EQ(0x07, value[2]);
    EXPECT_EQ(0x00, value[3]);
    callback_count++;
  };

  // Register the GATT service.
  GenericAttributeService gatt_service(&mgr, std::move(send_indication));

  // Enable Service Changed indications for the test client.
  att::ErrorCode ecode;
  WriteServiceChangedCCC(kTestPeerId, kEnableInd, &ecode);
  EXPECT_EQ(0, callback_count);

  constexpr UUID kTestSvcType((uint32_t)0xdeadbeef);
  constexpr IdType kChrcId = 0;
  constexpr uint8_t kChrcProps = Property::kRead;
  constexpr UUID kTestChrcType((uint32_t)0xdeadbeef);
  const att::AccessRequirements kReadReqs(true, true, true);
  const att::AccessRequirements kWriteReqs, kUpdateReqs;
  auto service = std::make_unique<Service>(false /* primary */, kTestSvcType);
  service->AddCharacteristic(
      std::make_unique<Characteristic>(kChrcId, kTestChrcType, kChrcProps, 0,
                                       kReadReqs, kWriteReqs, kUpdateReqs));
  auto service_id = mgr.RegisterService(std::move(service), NopReadHandler,
                                        NopWriteHandler, NopCCCallback);
  EXPECT_NE(0u, service_id);
  EXPECT_EQ(1, callback_count);
}

// Same test as above, but the indication is enabled just prior unregistering
// the latter test service.
TEST_F(GATT_GenericAttributeServiceTest, IndicateOnUnregister) {
  int callback_count = 0;
  auto send_indication = [&](PeerId peer_id, att::Handle handle,
                             const ByteBuffer& value) {
    EXPECT_EQ(kTestPeerId, peer_id);
    EXPECT_EQ(kChrcHandle, handle);
    ASSERT_EQ(4u, value.size());

    // The second service following the four-attribute GATT service should span
    // the subsequent four handles (update enabled).
    EXPECT_EQ(0x05, value[0]);
    EXPECT_EQ(0x00, value[1]);
    EXPECT_EQ(0x08, value[2]);
    EXPECT_EQ(0x00, value[3]);
    callback_count++;
  };

  // Register the GATT service.
  GenericAttributeService gatt_service(&mgr, std::move(send_indication));

  constexpr UUID kTestSvcType((uint32_t)0xdeadbeef);
  constexpr IdType kChrcId = 0;
  constexpr uint8_t kChrcProps = Property::kNotify;
  constexpr UUID kTestChrcType((uint32_t)0xdeadbeef);
  const att::AccessRequirements kReadReqs, kWriteReqs;
  const att::AccessRequirements kUpdateReqs(true, true, true);
  auto service = std::make_unique<Service>(false /* primary */, kTestSvcType);
  service->AddCharacteristic(
      std::make_unique<Characteristic>(kChrcId, kTestChrcType, kChrcProps, 0,
                                       kReadReqs, kWriteReqs, kUpdateReqs));
  auto service_id = mgr.RegisterService(std::move(service), NopReadHandler,
                                        NopWriteHandler, NopCCCallback);
  EXPECT_NE(0u, service_id);

  // Enable Service Changed indications for the test client.
  att::ErrorCode ecode;
  WriteServiceChangedCCC(kTestPeerId, kEnableInd, &ecode);
  EXPECT_EQ(0, callback_count);

  mgr.UnregisterService(service_id);
  EXPECT_EQ(1, callback_count);
}

}  // namespace
}  // namespace gatt
}  // namespace bt
