chromium/ash/webui/help_app_ui/search/search_tag_registry_unittest.cc

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

#include "ash/webui/help_app_ui/search/search_tag_registry.h"

#include "ash/webui/help_app_ui/search/search.mojom.h"
#include "ash/webui/help_app_ui/search/search_metadata.h"
#include "base/test/task_environment.h"
#include "chromeos/ash/components/local_search_service/public/mojom/index.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace ash::help_app {

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;
};

}  // namespace

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

  ~HelpAppSearchTagRegistryTest() override = default;

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

    local_search_service_proxy_->GetIndex(
        local_search_service::IndexId::kHelpAppLauncher,
        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::TaskEnvironment 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(HelpAppSearchTagRegistryTest, AddAndGet) {
  // Should be empty to start with.
  IndexGetSizeAndCheckResults(0u);
  EXPECT_EQ(0u, observer_.num_calls());

  // Add things to the registry.
  std::vector<mojom::SearchConceptPtr> to_add;
  mojom::SearchConceptPtr new_concept_1 = mojom::SearchConcept::New(
      /*id=*/"test-id-1",
      /*title=*/u"Title 1",
      /*main_category=*/u"Help",
      /*tags=*/std::vector<std::u16string>{u"Test tag", u"Tag 2"},
      /*tag_locale=*/"en",
      /*url_path_with_parameters=*/"help",
      /*locale=*/"");
  mojom::SearchConceptPtr new_concept_2 = mojom::SearchConcept::New(
      /*id=*/"test-id-2",
      /*title=*/u"Title 2",
      /*main_category=*/u"Help",
      /*tags=*/std::vector<std::u16string>{u"Another test tag"},
      /*tag_locale=*/"en",
      /*url_path_with_parameters=*/"help",
      /*locale=*/"");
  to_add.push_back(std::move(new_concept_1));
  to_add.push_back(std::move(new_concept_2));

  bool callback_done = false;
  search_tag_registry_.Update(
      to_add, base::BindOnce([](bool* callback_done) { *callback_done = true; },
                             &callback_done));
  task_environment_.RunUntilIdle();

  EXPECT_TRUE(callback_done);
  IndexGetSizeAndCheckResults(2u);
  EXPECT_EQ(1u, observer_.num_calls());

  // Get tag metadata for something that exists.
  auto& result1 = search_tag_registry_.GetTagMetadata("test-id-1");
  EXPECT_EQ(result1.title, u"Title 1");

  // Get tag metadata for something that doesn't exist.
  auto& result2 = search_tag_registry_.GetTagMetadata("not-found");
  EXPECT_EQ(&result2, &SearchTagRegistry::not_found_);
}

TEST_F(HelpAppSearchTagRegistryTest, MultipleUpdate) {
  // Add things to the registry.
  std::vector<mojom::SearchConceptPtr> to_add;
  mojom::SearchConceptPtr new_concept_1 = mojom::SearchConcept::New(
      /*id=*/"test-id-1",
      /*title=*/u"Title 1",
      /*main_category=*/u"Help",
      /*tags=*/std::vector<std::u16string>{u"Test tag", u"Tag 2"},
      /*tag_locale=*/"en",
      /*url_path_with_parameters=*/"help",
      /*locale=*/"");
  mojom::SearchConceptPtr new_concept_2 = mojom::SearchConcept::New(
      /*id=*/"test-id-2",
      /*title=*/u"Title 2",
      /*main_category=*/u"Help",
      /*tags=*/std::vector<std::u16string>{u"Another test tag"},
      /*tag_locale=*/"en",
      /*url_path_with_parameters=*/"help",
      /*locale=*/"");
  to_add.push_back(std::move(new_concept_1));
  to_add.push_back(std::move(new_concept_2));

  search_tag_registry_.Update(to_add, base::BindOnce([]() {}));
  task_environment_.RunUntilIdle();

  IndexGetSizeAndCheckResults(2u);
  EXPECT_EQ(1u, observer_.num_calls());

  // The second update has a concept that matches an existing id.
  std::vector<mojom::SearchConceptPtr> to_add_2;
  mojom::SearchConceptPtr new_concept_3 = mojom::SearchConcept::New(
      /*id=*/"test-id-1",  // Matches concept 1.
      /*title=*/u"Title 3",
      /*main_category=*/u"Help",
      /*tags=*/std::vector<std::u16string>{u"Test tag"},
      /*tag_locale=*/"en",
      /*url_path_with_parameters=*/"help",
      /*locale=*/"");
  mojom::SearchConceptPtr new_concept_4 = mojom::SearchConcept::New(
      /*id=*/"test-id-4",
      /*title=*/u"Title 4",
      /*main_category=*/u"Help",
      /*tags=*/std::vector<std::u16string>{u"Another test tag"},
      /*tag_locale=*/"en",
      /*url_path_with_parameters=*/"help",
      /*locale=*/"");
  to_add_2.push_back(std::move(new_concept_3));
  to_add_2.push_back(std::move(new_concept_4));

  search_tag_registry_.Update(to_add_2, base::BindOnce([]() {}));
  task_environment_.RunUntilIdle();

  IndexGetSizeAndCheckResults(3u);
  EXPECT_EQ(2u, observer_.num_calls());

  // The later concept should replace the earlier concept.
  auto& result = search_tag_registry_.GetTagMetadata("test-id-1");
  EXPECT_EQ(result.title, u"Title 3");
}

}  // namespace ash::help_app