text: // Copyright 2020 The Chromium 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 "chrome/services/sharing/nearby/test_support/fake_adapter.h"
  
  #include <memory>
  
  #include "base/containers/contains.h"
  #include "mojo/public/cpp/bindings/self_owned_receiver.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) {}
  
  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->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,
      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,
      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::SetShouldDiscoverySucceed(bool should_discovery_succeed) {
    should_discovery_succeed_ = should_discovery_succeed;
  }
  
  void FakeAdapter::SetAdvertisementDestroyedCallback(
      base::OnceClosure callback) {
    on_advertisement_destroyed_callback_ = std::move(callback);
  }
  
  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::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
  