text: // Copyright 2021 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 "chromeos/components/help_app_ui/search/search_tag_registry.h"
  
  #include "base/test/task_environment.h"
  #include "chromeos/components/help_app_ui/search/search.mojom.h"
  #include "chromeos/components/help_app_ui/search/search_metadata.h"
  #include "chromeos/components/local_search_service/public/mojom/index.mojom.h"
  #include "testing/gtest/include/gtest/gtest.h"
  
  namespace chromeos {
  namespace 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::kInvertedIndex,
          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"},
        /*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"},
        /*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"},
        /*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"},
        /*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"},
        /*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"},
        /*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 help_app
  }  // namespace chromeos
  