chromium/chromeos/ash/components/multidevice/remote_device_test_util.cc

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

#include "chromeos/ash/components/multidevice/remote_device_test_util.h"

#include <map>
#include <string>
#include <string_view>

#include "base/base64.h"
#include "base/base64url.h"
#include "base/strings/string_number_conversions.h"

namespace ash::multidevice {

namespace {

// Attributes of the default test remote device.
const char kTestRemoteDeviceUserId[] = "[email protected]";
const int64_t kTestRemoteDeviceInstanceId = 0L;
const char kTestRemoteDevicePiiFreeName[] = "no-pii device";
const char kTestRemoteDevicePSK[] = "remote device psk";
const int64_t kTestRemoteDeviceLastUpdateTimeMillis = 0L;
const char kBeaconSeedData[] = "beacon seed data";
const int64_t kBeaconSeedStartTimeMillis = 100L;
const int64_t kBeaconSeedEndTimeMillis = 200L;

// Create an Instance ID, which is a base64 URL-safe encoding of an 8-byte
// integer. This seems like overkill for tests, but some places in code might
// require the specific Instance ID formatting.
std::string InstanceIdFromInt64(int64_t number) {
  // Big-endian representation of |number|.
  uint8_t bytes[sizeof(int64_t)];
  bytes[0] = static_cast<uint8_t>((number >> 56) & 0xff);
  bytes[1] = static_cast<uint8_t>((number >> 48) & 0xff);
  bytes[2] = static_cast<uint8_t>((number >> 40) & 0xff);
  bytes[3] = static_cast<uint8_t>((number >> 32) & 0xff);
  bytes[4] = static_cast<uint8_t>((number >> 24) & 0xff);
  bytes[5] = static_cast<uint8_t>((number >> 16) & 0xff);
  bytes[6] = static_cast<uint8_t>((number >> 8) & 0xff);
  bytes[7] = static_cast<uint8_t>(number & 0xff);

  // Transforms the first 4 bits to 0x7 which is required for Instance IDs.
  bytes[0] &= 0x0f;
  bytes[0] |= 0x70;

  std::string iid;
  base::Base64UrlEncode(
      std::string_view(reinterpret_cast<const char*>(bytes), sizeof(bytes)),
      base::Base64UrlEncodePolicy::OMIT_PADDING, &iid);

  return iid;
}

}  // namespace

// Attributes of the default test remote device.
const char kTestRemoteDeviceName[] = "remote device";
const char kTestRemoteDevicePublicKey[] = "public key";
const char kTestRemoteDeviceBluetoothPublicAddress[] = "01:23:45:67:89:AB";

RemoteDeviceRefBuilder::RemoteDeviceRefBuilder() {
  remote_device_ = std::make_shared<RemoteDevice>(CreateRemoteDeviceForTest());
}

RemoteDeviceRefBuilder::~RemoteDeviceRefBuilder() = default;

RemoteDeviceRefBuilder& RemoteDeviceRefBuilder::SetUserEmail(
    const std::string& user_email) {
  remote_device_->user_email = user_email;
  return *this;
}

RemoteDeviceRefBuilder& RemoteDeviceRefBuilder::SetInstanceId(
    const std::string& instance_id) {
  remote_device_->instance_id = instance_id;
  return *this;
}

RemoteDeviceRefBuilder& RemoteDeviceRefBuilder::SetName(
    const std::string& name) {
  remote_device_->name = name;
  return *this;
}

RemoteDeviceRefBuilder& RemoteDeviceRefBuilder::SetPiiFreeName(
    const std::string& pii_free_name) {
  remote_device_->pii_free_name = pii_free_name;
  return *this;
}

RemoteDeviceRefBuilder& RemoteDeviceRefBuilder::SetPublicKey(
    const std::string& public_key) {
  remote_device_->public_key = public_key;
  return *this;
}

RemoteDeviceRefBuilder& RemoteDeviceRefBuilder::SetSupportsMobileHotspot(
    bool supports_mobile_hotspot) {
  remote_device_->software_features[SoftwareFeature::kInstantTetheringHost] =
      supports_mobile_hotspot ? SoftwareFeatureState::kSupported
                              : SoftwareFeatureState::kNotSupported;
  return *this;
}

RemoteDeviceRefBuilder& RemoteDeviceRefBuilder::SetSoftwareFeatureState(
    const SoftwareFeature feature,
    const SoftwareFeatureState new_state) {
  remote_device_->software_features[feature] = new_state;
  return *this;
}

RemoteDeviceRefBuilder& RemoteDeviceRefBuilder::SetLastUpdateTimeMillis(
    int64_t last_update_time_millis) {
  remote_device_->last_update_time_millis = last_update_time_millis;
  return *this;
}

RemoteDeviceRefBuilder& RemoteDeviceRefBuilder::SetBeaconSeeds(
    const std::vector<BeaconSeed>& beacon_seeds) {
  remote_device_->beacon_seeds = beacon_seeds;
  return *this;
}

RemoteDeviceRefBuilder& RemoteDeviceRefBuilder::SetBluetoothPublicAddress(
    const std::string& bluetooth_public_address) {
  remote_device_->bluetooth_public_address = bluetooth_public_address;
  return *this;
}

RemoteDeviceRef RemoteDeviceRefBuilder::Build() {
  return RemoteDeviceRef(remote_device_);
}

RemoteDevice CreateRemoteDeviceForTest() {
  std::map<SoftwareFeature, SoftwareFeatureState> software_features;
  software_features[SoftwareFeature::kSmartLockHost] =
      SoftwareFeatureState::kEnabled;
  software_features[SoftwareFeature::kInstantTetheringHost] =
      SoftwareFeatureState::kSupported;

  return RemoteDevice(
      kTestRemoteDeviceUserId, InstanceIdFromInt64(kTestRemoteDeviceInstanceId),
      kTestRemoteDeviceName, kTestRemoteDevicePiiFreeName,
      kTestRemoteDevicePublicKey, kTestRemoteDevicePSK,
      kTestRemoteDeviceLastUpdateTimeMillis, software_features,
      {multidevice::BeaconSeed(kBeaconSeedData,
                               base::Time::FromMillisecondsSinceUnixEpoch(
                                   kBeaconSeedStartTimeMillis),
                               base::Time::FromMillisecondsSinceUnixEpoch(
                                   kBeaconSeedEndTimeMillis))},
      kTestRemoteDeviceBluetoothPublicAddress);
}

RemoteDeviceRef CreateRemoteDeviceRefForTest() {
  return RemoteDeviceRefBuilder().Build();
}

RemoteDeviceRefList CreateRemoteDeviceRefListForTest(size_t num_to_create) {
  RemoteDeviceRefList generated_devices;

  for (size_t i = 0; i < num_to_create; i++) {
    RemoteDeviceRef remote_device =
        RemoteDeviceRefBuilder()
            .SetInstanceId(InstanceIdFromInt64(i))
            .SetPublicKey("publicKey" + base::NumberToString(i))
            .Build();
    generated_devices.push_back(remote_device);
  }

  return generated_devices;
}

RemoteDeviceList CreateRemoteDeviceListForTest(size_t num_to_create) {
  RemoteDeviceList generated_devices;

  for (size_t i = 0; i < num_to_create; i++) {
    RemoteDevice remote_device = CreateRemoteDeviceForTest();
    remote_device.instance_id = InstanceIdFromInt64(i);
    remote_device.public_key = "publicKey" + base::NumberToString(i);
    generated_devices.push_back(remote_device);
  }

  return generated_devices;
}

RemoteDevice* GetMutableRemoteDevice(const RemoteDeviceRef& remote_device_ref) {
  const RemoteDevice* remote_device = remote_device_ref.remote_device_.get();
  return const_cast<RemoteDevice*>(remote_device);
}

bool IsSameDevice(const RemoteDevice& remote_device,
                  RemoteDeviceRef remote_device_ref) {
  if (!remote_device_ref.remote_device_)
    return false;

  return remote_device == *remote_device_ref.remote_device_;
}

}  // namespace ash::multidevice