chromium/chrome/browser/ui/webui/ash/settings/search/search_tag_registry_unittest.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/browser/ui/webui/ash/settings/search/search_tag_registry.h"

#include "ash/webui/settings/public/constants/routes.mojom.h"
#include "base/no_destructor.h"
#include "base/test/task_environment.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/ui/webui/ash/settings/search/search_concept.h"
#include "chrome/grit/generated_resources.h"
#include "chromeos/ash/components/local_search_service/public/mojom/index.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace ash::settings {

namespace mojom {
using ::chromeos::settings::mojom::kPrintingDetailsSubpagePath;
using ::chromeos::settings::mojom::Setting;
using ::chromeos::settings::mojom::Subpage;
}  // namespace mojom

namespace {

class FakeObserver : public SearchTagRegistry::Observer {
 public:
  FakeObserver() = default;
  ~FakeObserver() override = default;

  size_t num_calls() const { return num_calls_; }

 private:
  // SearchTagRegistry::Observer:
  void OnRegistryUpdated() override { ++num_calls_; }

  size_t num_calls_ = 0;
};

// Note: Copied from printing_section.cc but does not need to stay in sync with
// it.
const std::vector<SearchConcept>& GetPrintingSearchConcepts() {
  static const base::NoDestructor<std::vector<SearchConcept>> tags({
      {IDS_OS_SETTINGS_TAG_PRINTING_ADD_PRINTER,
       mojom::kPrintingDetailsSubpagePath,
       mojom::SearchResultIcon::kPrinter,
       mojom::SearchResultDefaultRank::kMedium,
       mojom::SearchResultType::kSetting,
       {.setting = mojom::Setting::kAddPrinter}},
      {IDS_OS_SETTINGS_TAG_PRINTING_SAVED_PRINTERS,
       mojom::kPrintingDetailsSubpagePath,
       mojom::SearchResultIcon::kPrinter,
       mojom::SearchResultDefaultRank::kMedium,
       mojom::SearchResultType::kSetting,
       {.setting = mojom::Setting::kSavedPrinters}},
      {IDS_OS_SETTINGS_TAG_PRINTING,
       mojom::kPrintingDetailsSubpagePath,
       mojom::SearchResultIcon::kPrinter,
       mojom::SearchResultDefaultRank::kMedium,
       mojom::SearchResultType::kSubpage,
       {.subpage = mojom::Subpage::kPrintingDetails},
       {IDS_OS_SETTINGS_TAG_PRINTING_ALT1, IDS_OS_SETTINGS_TAG_PRINTING_ALT2,
        SearchConcept::kAltTagEnd}},
  });
  return *tags;
}

}  // namespace

class SearchTagRegistryTest : public testing::Test {
 protected:
  SearchTagRegistryTest()
      : search_tag_registry_(local_search_service_proxy_.get()) {}

  ~SearchTagRegistryTest() override = default;

  // testing::Test:
  void SetUp() override {
    search_tag_registry_.AddObserver(&observer_);

    local_search_service_proxy_->GetIndex(
        local_search_service::IndexId::kCrosSettings,
        local_search_service::Backend::kLinearMap,
        index_remote_.BindNewPipeAndPassReceiver());
  }

  void TearDown() override { search_tag_registry_.RemoveObserver(&observer_); }

  void IndexGetSizeAndCheckResults(uint32_t expected_num_items) {
    bool callback_done = false;
    uint32_t num_items = 0;
    index_remote_->GetSize(base::BindOnce(
        [](bool* callback_done, uint32_t* num_items, uint64_t size) {
          *callback_done = true;
          *num_items = size;
        },
        &callback_done, &num_items));
    task_environment_.RunUntilIdle();
    ASSERT_TRUE(callback_done);
    EXPECT_EQ(num_items, expected_num_items);
  }

  // This line should be before search_tag_registry_ is declared.
  base::test::SingleThreadTaskEnvironment task_environment_;
  std::unique_ptr<local_search_service::LocalSearchServiceProxy>
      local_search_service_proxy_ =
          std::make_unique<local_search_service::LocalSearchServiceProxy>(
              /*for_testing=*/true);
  SearchTagRegistry search_tag_registry_;
  FakeObserver observer_;
  mojo::Remote<local_search_service::mojom::Index> index_remote_;
};

TEST_F(SearchTagRegistryTest, AddAndRemove) {
  // Add search tags; size of the index should increase.
  {
    SearchTagRegistry::ScopedTagUpdater updater =
        search_tag_registry_.StartUpdate();
    updater.AddSearchTags(GetPrintingSearchConcepts());

    // Nothing should have happened yet, since |updater| has not gone out of
    // scope.
    IndexGetSizeAndCheckResults(0u);
    EXPECT_EQ(0u, observer_.num_calls());
  }
  // Now that it went out of scope, the update should have occurred.
  IndexGetSizeAndCheckResults(3u);
  EXPECT_EQ(1u, observer_.num_calls());

  std::string first_tag_id =
      SearchTagRegistry::ToResultId(GetPrintingSearchConcepts()[0]);

  // Tags added should be available via GetTagMetadata().
  const SearchConcept* add_printer_concept =
      search_tag_registry_.GetTagMetadata(first_tag_id);
  ASSERT_TRUE(add_printer_concept);
  EXPECT_EQ(mojom::Setting::kAddPrinter, add_printer_concept->id.setting);

  // Remove search tag; size should go back to 0.
  {
    SearchTagRegistry::ScopedTagUpdater updater =
        search_tag_registry_.StartUpdate();
    updater.RemoveSearchTags(GetPrintingSearchConcepts());

    // Tags should not have been removed yet, since |updater| has not gone out
    // of scope.
    IndexGetSizeAndCheckResults(3u);
    EXPECT_EQ(1u, observer_.num_calls());
  }
  // Now that it went out of scope, the update should have occurred.
  IndexGetSizeAndCheckResults(0u);
  EXPECT_EQ(2u, observer_.num_calls());

  // The tag should no longer be accessible via GetTagMetadata().
  add_printer_concept = search_tag_registry_.GetTagMetadata(first_tag_id);
  ASSERT_FALSE(add_printer_concept);
}

}  // namespace ash::settings