chromium/chrome/browser/ash/app_list/search/ranking/score_normalizing_ranker_unittest.cc

// Copyright 2022 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/ash/app_list/search/ranking/score_normalizing_ranker.h"

#include "base/files/scoped_temp_dir.h"
#include "base/logging.h"
#include "base/test/task_environment.h"
#include "chrome/browser/ash/app_list/search/chrome_search_result.h"
#include "chrome/browser/ash/app_list/search/search_controller.h"
#include "chrome/browser/ash/app_list/search/test/test_result.h"
#include "chrome/browser/ash/app_list/search/types.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace app_list::test {
namespace {

Results MakeResults(const std::vector<std::string>& ids,
                    const std::vector<double> scores,
                    ResultType result_type) {
  Results res;
  CHECK_EQ(ids.size(), scores.size());
  for (size_t i = 0; i < ids.size(); ++i) {
    auto result =
        std::make_unique<TestResult>(ids[i], result_type, Category::kUnknown,
                                     /*display_score=*/scores[i]);
    result->set_relevance(scores[i]);
    res.push_back(std::move(result));
  }
  return res;
}

}  // namespace

class ScoreNormalizingRankerTest : public testing::Test {
 public:
  void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); }

  void Wait() { task_environment_.RunUntilIdle(); }

  base::FilePath GetPath() { return temp_dir_.GetPath().Append("proto"); }

  ash::PersistentProto<ScoreNormalizerProto> GetProto() {
    return ash::PersistentProto<ScoreNormalizerProto>(GetPath(),
                                                      base::Seconds(0));
  }

  base::test::TaskEnvironment task_environment_{
      base::test::TaskEnvironment::MainThreadType::UI,
      base::test::TaskEnvironment::ThreadPoolExecutionMode::QUEUED,
      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
  base::ScopedTempDir temp_dir_;
};

TEST_F(ScoreNormalizingRankerTest, UpdateResultRanks) {
  ScoreNormalizingRanker ranker(ScoreNormalizer::Params(), GetProto());
  Wait();

  ResultsMap results;
  results[ResultType::kInstalledApp] = MakeResults(
      {"a", "b", "c", "d", "e", "f", "g"},
      {0.4, 0.2, 0.3, 0.25, 0.35, 0.1, 0.33}, ResultType::kInstalledApp);
  results[ResultType::kFileSearch] =
      MakeResults({"h", "i"}, {1.0, 2.0}, ResultType::kFileSearch);

  ranker.UpdateResultRanks(results, ResultType::kInstalledApp);

  // App results should have been scored, but their precise scoring is up to the
  // implementation of the score normalizer itself. Let its tests cover this,
  // and just check that the results have been scored at all, and the results
  // are ordered by relevance after normalization.
  const auto& app_results = results[ResultType::kInstalledApp];
  for (size_t i = 0; i < 4; ++i) {
    EXPECT_GT(app_results[i]->scoring().normalized_relevance(), 0.0);
  }

  std::vector<ChromeSearchResult*> ordered_app_results;
  for (const auto& result : app_results) {
    ordered_app_results.push_back(result.get());
  }

  std::sort(ordered_app_results.begin(), ordered_app_results.end(),
            [](const auto& r1, const auto& r2) {
              return r1->scoring().normalized_relevance() >
                     r2->scoring().normalized_relevance();
            });

  std::vector<std::string> ordered_app_result_ids;
  for (const auto* result : ordered_app_results) {
    ordered_app_result_ids.push_back(result->id());
  }

  EXPECT_EQ(std::vector<std::string>({"a", "e", "g", "c", "d", "b", "f"}),
            ordered_app_result_ids);

  // File results should not have been scored.
  const auto& file_results = results[ResultType::kFileSearch];
  EXPECT_FLOAT_EQ(file_results[0]->scoring().normalized_relevance(), 0.0);
  EXPECT_FLOAT_EQ(file_results[1]->scoring().normalized_relevance(), 0.0);
}

}  // namespace app_list::test