blob: b7366a21ef284172c06a953316d0c69d23748c18 [file] [log] [blame]
// Copyright 2020 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 "chrome/browser/ui/commander/fuzzy_finder.h"
#include "base/i18n/case_conversion.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace commander {
namespace {
// Convenience function to avoid visual noise from constructing FuzzyFinder
// objects in-test.
double FuzzyFind(const std::u16string& needle,
const std::u16string& haystack,
std::vector<gfx::Range>* matched_ranges) {
return FuzzyFinder(needle).Find(haystack, matched_ranges);
}
} // namespace
TEST(CommanderFuzzyFinder, NonmatchIsZero) {
std::vector<gfx::Range> ranges;
EXPECT_EQ(0, FuzzyFind(u"orange", u"orangutan", &ranges));
EXPECT_TRUE(ranges.empty());
EXPECT_EQ(0, FuzzyFind(u"elephant", u"orangutan", &ranges));
EXPECT_TRUE(ranges.empty());
}
TEST(CommanderFuzzyFinder, ExactMatchIsOne) {
std::vector<gfx::Range> ranges;
EXPECT_EQ(1, FuzzyFind(u"orange", u"orange", &ranges));
EXPECT_EQ(ranges, std::vector<gfx::Range>({{0, 6}}));
}
// This ensures coverage for a fast path. Successful match is
// tested in ExactMatchIsOne() above.
TEST(CommanderFuzzyFinder, NeedleHaystackSameLength) {
std::vector<gfx::Range> ranges;
EXPECT_EQ(0, FuzzyFind(u"ranges", u"orange", &ranges));
EXPECT_TRUE(ranges.empty());
}
// This ensures coverage for a fast path (just making sure the path has
// coverage rather than ensuring the path is taken).
TEST(CommanderFuzzyFinder, SingleCharNeedle) {
std::vector<gfx::Range> ranges;
FuzzyFinder finder(u"o");
double prefix_score = finder.Find(u"orange", &ranges);
EXPECT_EQ(ranges, std::vector<gfx::Range>({{0, 1}}));
double internal_score = finder.Find(u"phone", &ranges);
EXPECT_EQ(ranges, std::vector<gfx::Range>({{2, 3}}));
double boundary_score = finder.Find(u"phone operator", &ranges);
EXPECT_EQ(ranges, std::vector<gfx::Range>({{6, 7}}));
// Expected ordering:
// - Prefix should rank highest.
// - Word boundary matches that are not the prefix should rank next
// highest, even if there's an internal match earlier in the haystack.
// - Internal matches should rank lowest.
EXPECT_GT(prefix_score, boundary_score);
EXPECT_GT(boundary_score, internal_score);
// ...and non-matches should have score = 0.
EXPECT_EQ(0, finder.Find(u"aquarium", &ranges));
EXPECT_TRUE(ranges.empty());
}
TEST(CommanderFuzzyFinder, CaseInsensitive) {
std::vector<gfx::Range> ranges;
EXPECT_EQ(1, FuzzyFind(u"orange", u"Orange", &ranges));
EXPECT_EQ(ranges, std::vector<gfx::Range>({{0, 6}}));
}
TEST(CommanderFuzzyFinder, PrefixRanksHigherThanInternal) {
std::vector<gfx::Range> ranges;
FuzzyFinder finder(u"orange");
double prefix_rank = finder.Find(u"Orange juice", &ranges);
double non_prefix_rank = finder.Find(u"William of Orange", &ranges);
EXPECT_GT(prefix_rank, 0);
EXPECT_GT(non_prefix_rank, 0);
EXPECT_LT(prefix_rank, 1);
EXPECT_LT(non_prefix_rank, 1);
EXPECT_GT(prefix_rank, non_prefix_rank);
}
TEST(CommanderFuzzyFinder, NeedleLongerThanHaystack) {
std::vector<gfx::Range> ranges;
EXPECT_EQ(0, FuzzyFind(u"orange juice", u"orange", &ranges));
EXPECT_TRUE(ranges.empty());
}
TEST(CommanderFuzzyFinder, Noncontiguous) {
std::vector<gfx::Range> ranges;
EXPECT_GT(FuzzyFind(u"tuot", u"Tlön, Uqbar, Orbis Tertius", &ranges), 0);
EXPECT_EQ(ranges,
std::vector<gfx::Range>({{0, 1}, {6, 7}, {13, 14}, {19, 20}}));
}
TEST(CommanderFuzzyFinder, EmptyStringDoesNotMatch) {
std::vector<gfx::Range> ranges;
EXPECT_EQ(0, FuzzyFind(u"", u"orange", &ranges));
EXPECT_TRUE(ranges.empty());
}
} // namespace commander