chromium/chrome/services/sharing/nearby/test_support/fake_adapter.cc

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/services/sharing/nearby/test_support/fake_adapter.h"

#include <memory>

#include "base/containers/contains.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace bluetooth {

namespace {

class FakeAdvertisement : public mojom::Advertisement {
 public:
  explicit FakeAdvertisement(base::OnceClosure on_destroy_callback)
      : on_destroy_callback_(std::move(on_destroy_callback)) {}
  ~FakeAdvertisement() override { std::move(on_destroy_callback_).Run(); }

 private:
  // mojom::Advertisement:
  void Unregister(UnregisterCallback callback) override {
    std::move(callback).Run();
  }

  base::OnceClosure on_destroy_callback_;
};

class FakeDiscoverySession : public mojom::DiscoverySession {
 public:
  explicit FakeDiscoverySession(base::OnceClosure on_destroy_callback)
      : on_destroy_callback_(std::move(on_destroy_callback)) {}
  ~FakeDiscoverySession() override { std::move(on_destroy_callback_).Run(); }

 private:
  // mojom::DiscoverySession:
  void IsActive(IsActiveCallback callback) override {
    std::move(callback).Run(true);
  }
  void Stop(StopCallback callback) override { std::move(callback).Run(true); }

  base::OnceClosure on_destroy_callback_;
};

class FakeSocket : public mojom::Socket {
 public:
  FakeSocket(mojo::ScopedDataPipeProducerHandle receive_stream,
             mojo::ScopedDataPipeConsumerHandle send_stream)
      : receive_stream_(std::move(receive_stream)),
        send_stream_(std::move(send_stream)) {}
  ~FakeSocket() override = default;

 private:
  // mojom::Socket:
  void Disconnect(DisconnectCallback callback) override {
    std::move(callback).Run();
  }

  mojo::ScopedDataPipeProducerHandle receive_stream_;
  mojo::ScopedDataPipeConsumerHandle send_stream_;
};

class FakeServerSocket : public mojom::ServerSocket {
 public:
  FakeServerSocket() = default;
  ~FakeServerSocket() override = default;

 private:
  // mojom::ServerSocket:
  void Accept(AcceptCallback callback) override {
    std::move(callback).Run(/*result=*/nullptr);
  }
  void Disconnect(DisconnectCallback callback) override {
    std::move(callback).Run();
  }
};

}  // namespace

FakeAdapter::FakeAdapter() = default;

FakeAdapter::~FakeAdapter() = default;

void FakeAdapter::ConnectToDevice(const std::string& address,
                                  ConnectToDeviceCallback callback) {
  if (connect_to_device_result_ == bluetooth::mojom::ConnectResult::SUCCESS) {
    mojo::PendingRemote<mojom::Device> pending_device;
    mojo::MakeSelfOwnedReceiver(
        std::move(fake_device_),
        pending_device.InitWithNewPipeAndPassReceiver());
    std::move(callback).Run(connect_to_device_result_,
                            std::move(pending_device));
    return;
  }

  std::move(callback).Run(connect_to_device_result_, mojo::NullRemote());
}

void FakeAdapter::GetDevices(GetDevicesCallback callback) {}

void FakeAdapter::GetInfo(GetInfoCallback callback) {
  mojom::AdapterInfoPtr adapter_info = mojom::AdapterInfo::New();
  adapter_info->address = address_;
  adapter_info->name = name_;
  adapter_info->extended_advertisement_support =
      extended_advertisement_support_;
  adapter_info->present = present_;
  adapter_info->powered = powered_;
  adapter_info->discoverable = discoverable_;
  adapter_info->discovering = discovering_;
  std::move(callback).Run(std::move(adapter_info));
}

void FakeAdapter::AddObserver(
    mojo::PendingRemote<mojom::AdapterObserver> observer,
    AddObserverCallback callback) {
  observers_.Add(std::move(observer));
  std::move(callback).Run();
}

void FakeAdapter::RegisterAdvertisement(
    const device::BluetoothUUID& service_uuid,
    const std::vector<uint8_t>& service_data,
    bool use_scan_response,
    bool connectable,
    RegisterAdvertisementCallback callback) {
  if (!should_advertisement_registration_succeed_) {
    std::move(callback).Run(mojo::NullRemote());
    return;
  }

  registered_advertisements_map_.insert({service_uuid, service_data});

  auto advertisement = std::make_unique<FakeAdvertisement>(
      base::BindOnce(&FakeAdapter::OnAdvertisementDestroyed,
                     base::Unretained(this), service_uuid));

  mojo::PendingRemote<mojom::Advertisement> pending_advertisement;
  mojo::MakeSelfOwnedReceiver(
      std::move(advertisement),
      pending_advertisement.InitWithNewPipeAndPassReceiver());

  std::move(callback).Run(std::move(pending_advertisement));
}

void FakeAdapter::SetDiscoverable(bool discoverable,
                                  SetDiscoverableCallback callback) {
  discoverable_ = discoverable;
  std::move(callback).Run(/*success=*/true);
}

void FakeAdapter::SetName(const std::string& name, SetNameCallback callback) {
  name_ = name;
  std::move(callback).Run(/*success=*/true);
}

void FakeAdapter::StartDiscoverySession(
    const std::string& client_name,
    StartDiscoverySessionCallback callback) {
  DCHECK(!discovery_session_);

  if (!should_discovery_succeed_) {
    std::move(callback).Run(std::move(mojo::NullRemote()));
    return;
  }

  auto discovery_session =
      std::make_unique<FakeDiscoverySession>(base::BindOnce(
          &FakeAdapter::OnDiscoverySessionDestroyed, base::Unretained(this)));
  discovery_session_ = discovery_session.get();

  mojo::PendingRemote<mojom::DiscoverySession> pending_session;
  mojo::MakeSelfOwnedReceiver(std::move(discovery_session),
                              pending_session.InitWithNewPipeAndPassReceiver());

  std::move(callback).Run(std::move(pending_session));
}

void FakeAdapter::ConnectToServiceInsecurely(
    const std::string& address,
    const device::BluetoothUUID& service_uuid,
    bool should_unbond_on_error,
    ConnectToServiceInsecurelyCallback callback) {
  if (!base::Contains(allowed_connections_for_address_and_uuid_pair_,
                      std::make_pair(address, service_uuid))) {
    std::move(callback).Run(/*result=*/nullptr);
    return;
  }

  mojo::ScopedDataPipeProducerHandle receive_pipe_producer_handle;
  mojo::ScopedDataPipeConsumerHandle receive_pipe_consumer_handle;
  ASSERT_EQ(MOJO_RESULT_OK, mojo::CreateDataPipe(/*options=*/nullptr,
                                                 receive_pipe_producer_handle,
                                                 receive_pipe_consumer_handle));

  mojo::ScopedDataPipeProducerHandle send_pipe_producer_handle;
  mojo::ScopedDataPipeConsumerHandle send_pipe_consumer_handle;
  ASSERT_EQ(MOJO_RESULT_OK,
            mojo::CreateDataPipe(/*options=*/nullptr, send_pipe_producer_handle,
                                 send_pipe_consumer_handle));

  mojo::PendingRemote<mojom::Socket> pending_socket;

  mojo::MakeSelfOwnedReceiver(
      std::make_unique<FakeSocket>(std::move(receive_pipe_producer_handle),
                                   std::move(send_pipe_consumer_handle)),
      pending_socket.InitWithNewPipeAndPassReceiver());

  mojom::ConnectToServiceResultPtr connect_to_service_result =
      mojom::ConnectToServiceResult::New();
  connect_to_service_result->socket = std::move(pending_socket);
  connect_to_service_result->receive_stream =
      std::move(receive_pipe_consumer_handle);
  connect_to_service_result->send_stream = std::move(send_pipe_producer_handle);
  std::move(callback).Run(std::move(connect_to_service_result));
}

void FakeAdapter::CreateRfcommServiceInsecurely(
    const std::string& service_name,
    const device::BluetoothUUID& service_uuid,
    CreateRfcommServiceInsecurelyCallback callback) {
  if (!base::Contains(allowed_connections_for_service_name_and_uuid_pair_,
                      std::make_pair(service_name, service_uuid))) {
    std::move(callback).Run(/*server_socket=*/mojo::NullRemote());
    return;
  }

  mojo::PendingRemote<mojom::ServerSocket> pending_server_socket;

  mojo::MakeSelfOwnedReceiver(
      std::make_unique<FakeServerSocket>(),
      pending_server_socket.InitWithNewPipeAndPassReceiver());

  std::move(callback).Run(std::move(pending_server_socket));
}

void FakeAdapter::CreateLocalGattService(
    const device::BluetoothUUID& service_id,
    mojo::PendingRemote<mojom::GattServiceObserver> observer,
    CreateLocalGattServiceCallback callback) {
  mojo::PendingRemote<mojom::GattService> pending_gatt_service;
  fake_gatt_service_->SetObserver(std::move(observer));
  gatt_service_receiver_ = mojo::MakeSelfOwnedReceiver(
      std::move(fake_gatt_service_),
      pending_gatt_service.InitWithNewPipeAndPassReceiver());
  std::move(callback).Run(std::move(pending_gatt_service));

  if (create_local_gatt_service_callback_) {
    std::move(create_local_gatt_service_callback_).Run();
  }
}

void FakeAdapter::SetShouldAdvertisementRegistrationSucceed(
    bool should_advertisement_registration_succeed) {
  should_advertisement_registration_succeed_ =
      should_advertisement_registration_succeed;
}

void FakeAdapter::IsLeScatternetDualRoleSupported(
    IsLeScatternetDualRoleSupportedCallback callback) {
  std::move(callback).Run(is_dual_role_supported_);
}

void FakeAdapter::SetShouldDiscoverySucceed(bool should_discovery_succeed) {
  should_discovery_succeed_ = should_discovery_succeed;
}

void FakeAdapter::SetAdvertisementDestroyedCallback(
    base::OnceClosure callback) {
  on_advertisement_destroyed_callback_ = std::move(callback);
}

void FakeAdapter::SetCreateLocalGattServiceCallback(
    base::OnceClosure callback) {
  create_local_gatt_service_callback_ = std::move(callback);
}

void FakeAdapter::SetCreateLocalGattServiceResult(
    std::unique_ptr<FakeGattService> fake_gatt_service) {
  fake_gatt_service_ = std::move(fake_gatt_service);
}

void FakeAdapter::SetExtendedAdvertisementSupport(
    bool extended_advertisement_support) {
  extended_advertisement_support_ = extended_advertisement_support;
}

const std::vector<uint8_t>* FakeAdapter::GetRegisteredAdvertisementServiceData(
    const device::BluetoothUUID& service_uuid) {
  auto it = registered_advertisements_map_.find(service_uuid);
  return it == registered_advertisements_map_.end() ? nullptr : &it->second;
}

void FakeAdapter::SetDiscoverySessionDestroyedCallback(
    base::OnceClosure callback) {
  on_discovery_session_destroyed_callback_ = std::move(callback);
}

bool FakeAdapter::IsDiscoverySessionActive() {
  return discovery_session_;
}

void FakeAdapter::NotifyDeviceAdded(mojom::DeviceInfoPtr device_info) {
  for (auto& observer : observers_)
    observer->DeviceAdded(device_info->Clone());
}

void FakeAdapter::NotifyDeviceChanged(mojom::DeviceInfoPtr device_info) {
  for (auto& observer : observers_)
    observer->DeviceChanged(device_info->Clone());
}

void FakeAdapter::NotifyDeviceRemoved(mojom::DeviceInfoPtr device_info) {
  for (auto& observer : observers_)
    observer->DeviceRemoved(device_info->Clone());
}

void FakeAdapter::AllowConnectionForAddressAndUuidPair(
    const std::string& address,
    const device::BluetoothUUID& service_uuid) {
  allowed_connections_for_address_and_uuid_pair_.emplace(address, service_uuid);
}

void FakeAdapter::AllowIncomingConnectionForServiceNameAndUuidPair(
    const std::string& service_name,
    const device::BluetoothUUID& service_uuid) {
  allowed_connections_for_service_name_and_uuid_pair_.emplace(service_name,
                                                              service_uuid);
}

void FakeAdapter::SetConnectToDeviceResult(
    bluetooth::mojom::ConnectResult result,
    std::unique_ptr<FakeDevice> fake_device) {
  connect_to_device_result_ = result;
  fake_device_ = std::move(fake_device);
}

void FakeAdapter::OnAdvertisementDestroyed(
    const device::BluetoothUUID& service_uuid) {
  DCHECK(!registered_advertisements_map_.empty());
  registered_advertisements_map_.erase(service_uuid);
  if (on_advertisement_destroyed_callback_)
    std::move(on_advertisement_destroyed_callback_).Run();
}

void FakeAdapter::OnDiscoverySessionDestroyed() {
  DCHECK(discovery_session_);
  discovery_session_ = nullptr;
  if (on_discovery_session_destroyed_callback_)
    std::move(on_discovery_session_destroyed_callback_).Run();
}

}  // namespace bluetooth