chromium/components/services/app_service/public/cpp/shortcut/shortcut_registry_cache_unittest.cc

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

#include "components/services/app_service/public/cpp/shortcut/shortcut_registry_cache.h"

#include <memory>
#include <utility>

#include "base/scoped_observation.h"
#include "components/services/app_service/public/cpp/icon_effects.h"
#include "components/services/app_service/public/cpp/shortcut/shortcut.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace apps {

class ShortcutRegistryCacheTest : public testing::Test,
                                  public ShortcutRegistryCache::Observer {
 public:
  ShortcutRegistryCache& cache() { return cache_; }

 protected:
  void ExpectShortcutUpdate(std::unique_ptr<ShortcutUpdate> update) {
    expected_update_ = std::move(update);
    if (!obs_.IsObserving()) {
      obs_.Observe(&cache());
    }
    on_shortcut_updated_called_ = false;
  }
  bool OnShortcutUpdatedCalled() { return on_shortcut_updated_called_; }

  void ExpectShortcutRemoved(const ShortcutId& shortcut_id) {
    expected_shortcut_id_ = shortcut_id;
    if (!obs_.IsObserving()) {
      obs_.Observe(&cache());
    }
    on_shortcut_removed_called_ = false;
  }
  bool OnShortcutRemovedCalled() { return on_shortcut_removed_called_; }

 private:
  void OnShortcutUpdated(const ShortcutUpdate& update) override {
    on_shortcut_updated_called_ = true;
    EXPECT_EQ(update, *expected_update_);

    // Verified the data in shortcut registry cache is already updated.
    ASSERT_TRUE(cache().HasShortcut(update.ShortcutId()));
    ShortcutView shortcut_in_cache = cache().GetShortcut(update.ShortcutId());
    EXPECT_EQ(shortcut_in_cache->shortcut_id, update.ShortcutId());
    EXPECT_EQ(shortcut_in_cache->name, update.Name());
    EXPECT_EQ(shortcut_in_cache->shortcut_source, update.ShortcutSource());
    EXPECT_EQ(shortcut_in_cache->icon_key, update.IconKey());
  }

  void OnShortcutRemoved(const ShortcutId& shortcut_id) override {
    on_shortcut_removed_called_ = true;
    EXPECT_EQ(shortcut_id, expected_shortcut_id_);

    // Verified the data in shortcut registry cache is already updated.
    ASSERT_FALSE(cache().HasShortcut(shortcut_id));
  }

  void OnShortcutRegistryCacheWillBeDestroyed(
      ShortcutRegistryCache* cache) override {
    obs_.Reset();
  }
  ShortcutRegistryCache cache_;
  std::unique_ptr<ShortcutUpdate> expected_update_;
  ShortcutId expected_shortcut_id_;
  bool on_shortcut_updated_called_ = false;
  bool on_shortcut_removed_called_ = false;
  base::ScopedObservation<ShortcutRegistryCache,
                          ShortcutRegistryCache::Observer>
      obs_{this};
};

TEST_F(ShortcutRegistryCacheTest, AddShortcut) {
  std::string host_app_id = "host_app_id";
  std::string local_id = "local_id";
  auto shortcut = std::make_unique<Shortcut>(host_app_id, local_id);
  ShortcutId shortcut_id = shortcut->shortcut_id;
  shortcut->name = "name";
  shortcut->shortcut_source = ShortcutSource::kUser;
  shortcut->icon_key = IconKey();
  shortcut->icon_key->update_version = false;

  EXPECT_FALSE(cache().HasShortcut(shortcut_id));
  cache().UpdateShortcut(std::move(shortcut));
  ASSERT_TRUE(cache().HasShortcut(shortcut_id));

  ShortcutView stored_shortcut = cache().GetShortcut(shortcut_id);

  ASSERT_TRUE(stored_shortcut);
  EXPECT_EQ(stored_shortcut->shortcut_id, shortcut_id);
  EXPECT_EQ(stored_shortcut->name, "name");
  EXPECT_EQ(stored_shortcut->shortcut_source, ShortcutSource::kUser);
  EXPECT_EQ(stored_shortcut->host_app_id, host_app_id);
  EXPECT_EQ(stored_shortcut->local_id, local_id);
  IconKey icon_key;
  icon_key.update_version = IconKey::kInitVersion;
  EXPECT_EQ(stored_shortcut->icon_key, icon_key);

  EXPECT_EQ(cache().GetAllShortcuts().size(), 1u);
}

TEST_F(ShortcutRegistryCacheTest, UpdateShortcut) {
  std::string host_app_id = "host_app_id";
  std::string local_id = "local_id";
  auto shortcut = std::make_unique<Shortcut>(host_app_id, local_id);
  ShortcutId shortcut_id = shortcut->shortcut_id;
  shortcut->name = "name";
  shortcut->shortcut_source = ShortcutSource::kUser;
  shortcut->icon_key = IconKey();
  shortcut->icon_key->update_version = false;

  EXPECT_FALSE(cache().HasShortcut(shortcut_id));
  cache().UpdateShortcut(std::move(shortcut));
  ASSERT_TRUE(cache().HasShortcut(shortcut_id));

  EXPECT_EQ(cache().GetAllShortcuts().size(), 1u);

  auto shortcut_delta = std::make_unique<Shortcut>(host_app_id, local_id);
  shortcut_delta->name = "new name";
  shortcut_delta->shortcut_source = ShortcutSource::kPolicy;
  shortcut_delta->icon_key =
      IconKey(IconKey::kInvalidResourceId, IconEffects::kCrOsStandardIcon);
  shortcut_delta->icon_key->update_version = true;

  cache().UpdateShortcut(std::move(shortcut_delta));

  EXPECT_EQ(cache().GetAllShortcuts().size(), 1u);

  ShortcutView stored_shortcut = cache().GetShortcut(shortcut_id);

  ASSERT_TRUE(stored_shortcut);
  EXPECT_EQ(stored_shortcut->shortcut_id, shortcut_id);
  EXPECT_EQ(stored_shortcut->name, "new name");
  EXPECT_EQ(stored_shortcut->shortcut_source, ShortcutSource::kPolicy);
  EXPECT_EQ(stored_shortcut->host_app_id, host_app_id);
  EXPECT_EQ(stored_shortcut->local_id, local_id);
  IconKey icon_key(IconKey::kInvalidResourceId, IconEffects::kCrOsStandardIcon);
  icon_key.update_version = IconKey::kInitVersion + 1;
  EXPECT_EQ(stored_shortcut->icon_key, icon_key);
}

TEST_F(ShortcutRegistryCacheTest, RemoveShortcut) {
  std::string host_app_id = "host_app_id";
  std::string local_id = "local_id";
  auto shortcut = std::make_unique<Shortcut>(host_app_id, local_id);
  ShortcutId shortcut_id = shortcut->shortcut_id;
  shortcut->name = "name";
  shortcut->shortcut_source = ShortcutSource::kUser;
  shortcut->icon_key = IconKey();
  shortcut->icon_key->update_version = false;

  cache().UpdateShortcut(std::move(shortcut));
  ASSERT_TRUE(cache().HasShortcut(shortcut_id));
  ASSERT_EQ(cache().GetAllShortcuts().size(), 1u);

  cache().RemoveShortcut(shortcut_id);

  EXPECT_EQ(cache().GetAllShortcuts().size(), 0u);
  EXPECT_FALSE(cache().HasShortcut(shortcut_id));
}

TEST_F(ShortcutRegistryCacheTest, Observer) {
  std::string host_app_id = "host_app_id";
  std::string local_id = "local_id";
  auto shortcut = std::make_unique<Shortcut>(host_app_id, local_id);
  ShortcutId shortcut_id = shortcut->shortcut_id;
  shortcut->name = "name";
  shortcut->shortcut_source = ShortcutSource::kUser;
  shortcut->icon_key = IconKey();
  shortcut->icon_key->update_version = false;
  ExpectShortcutUpdate(
      std::make_unique<ShortcutUpdate>(nullptr, shortcut.get()));
  ASSERT_NO_FATAL_FAILURE(cache().UpdateShortcut(std::move(shortcut)));
  EXPECT_TRUE(OnShortcutUpdatedCalled());

  auto shortcut_delta = std::make_unique<Shortcut>(host_app_id, local_id);
  shortcut_delta->name = "new name";
  shortcut_delta->shortcut_source = ShortcutSource::kPolicy;
  shortcut_delta->icon_key = IconKey(/*resource_id=*/1, /*icon_effects=*/1);
  shortcut_delta->icon_key->update_version = false;
  std::unique_ptr<Shortcut> current_state =
      cache().GetShortcut(shortcut_id)->Clone();
  ExpectShortcutUpdate(std::make_unique<ShortcutUpdate>(current_state.get(),
                                                        shortcut_delta.get()));
  ASSERT_NO_FATAL_FAILURE(cache().UpdateShortcut(std::move(shortcut_delta)));
  EXPECT_TRUE(OnShortcutUpdatedCalled());

  auto shortcut_nochange = std::make_unique<Shortcut>(host_app_id, local_id);
  current_state = cache().GetShortcut(shortcut_id)->Clone();
  ExpectShortcutUpdate(std::make_unique<ShortcutUpdate>(
      current_state.get(), shortcut_nochange.get()));
  ASSERT_NO_FATAL_FAILURE(cache().UpdateShortcut(std::move(shortcut_nochange)));
  EXPECT_TRUE(OnShortcutUpdatedCalled());

  ExpectShortcutRemoved(shortcut_id);
  ASSERT_NO_FATAL_FAILURE(cache().RemoveShortcut(shortcut_id));
  EXPECT_TRUE(OnShortcutRemovedCalled());
}

TEST_F(ShortcutRegistryCacheTest, GetHostAppId) {
  std::string host_app_id = "host_app_id";
  std::string local_id = "local_id";
  auto shortcut = std::make_unique<Shortcut>(host_app_id, local_id);
  ShortcutId shortcut_id = shortcut->shortcut_id;

  ASSERT_FALSE(cache().HasShortcut(shortcut_id));
  EXPECT_EQ(cache().GetShortcutHostAppId(shortcut_id), "");

  cache().UpdateShortcut(std::move(shortcut));
  ASSERT_TRUE(cache().HasShortcut(shortcut_id));
  EXPECT_EQ(cache().GetShortcutHostAppId(shortcut_id), "host_app_id");
}

TEST_F(ShortcutRegistryCacheTest, GetLocalId) {
  std::string host_app_id = "host_app_id";
  std::string local_id = "local_id";
  auto shortcut = std::make_unique<Shortcut>(host_app_id, local_id);
  ShortcutId shortcut_id = shortcut->shortcut_id;

  ASSERT_FALSE(cache().HasShortcut(shortcut_id));
  EXPECT_EQ(cache().GetShortcutLocalId(shortcut_id), "");

  cache().UpdateShortcut(std::move(shortcut));
  ASSERT_TRUE(cache().HasShortcut(shortcut_id));
  EXPECT_EQ(cache().GetShortcutLocalId(shortcut_id), "local_id");
}

}  // namespace apps