// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromeos/ash/components/string_matching/sequence_matcher.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace ash::string_matching {
namespace {
using Match = SequenceMatcher::Match;
bool MatchEqual(const Match& match1, const Match& match2) {
return match1.pos_first_string == match2.pos_first_string &&
match1.pos_second_string == match2.pos_second_string &&
match1.length == match2.length;
}
} // namespace
class SequenceMatcherTest : public testing::Test {};
TEST_F(SequenceMatcherTest, TestFindLongestMatch) {
SequenceMatcher sequence_match(u"miscellanious", u"miscellaneous", 0.0);
ASSERT_TRUE(MatchEqual(sequence_match.FindLongestMatch(0, 13, 0, 13),
Match(0, 0, 9)));
ASSERT_TRUE(MatchEqual(sequence_match.FindLongestMatch(7, 13, 7, 13),
Match(10, 10, 3)));
ASSERT_TRUE(MatchEqual(
SequenceMatcher(u"", u"abcd", 0.0).FindLongestMatch(0, 0, 0, 4),
Match(0, 0, 0)));
ASSERT_TRUE(MatchEqual(SequenceMatcher(u"abababbababa", u"ababbaba", 0.0)
.FindLongestMatch(0, 12, 0, 8),
Match(2, 0, 8)));
ASSERT_TRUE(MatchEqual(
SequenceMatcher(u"aaaaaa", u"aaaaa", 0.0).FindLongestMatch(0, 6, 0, 5),
Match(0, 0, 5)));
}
TEST_F(SequenceMatcherTest, TestGetMatchingBlocks) {
SequenceMatcher sequence_match(u"This is a demo sentence!!!",
u"This demo sentence is good!!!", 0.0);
const std::vector<Match> true_matches = {Match(0, 0, 4), Match(9, 4, 14),
Match(23, 26, 3), Match(26, 29, 0)};
const std::vector<Match> matches = sequence_match.GetMatchingBlocks();
ASSERT_EQ(matches.size(), 4ul);
for (int i = 0; i < 4; i++) {
ASSERT_TRUE(MatchEqual(matches[i], true_matches[i]));
}
}
TEST_F(SequenceMatcherTest, TestSequenceMatcherRatio) {
ASSERT_EQ(SequenceMatcher(u"abcd", u"adbc", 0.0).Ratio(), 0.75);
ASSERT_EQ(SequenceMatcher(u"white cats", u"cats white", 0.0).Ratio(), 0.5);
}
TEST_F(SequenceMatcherTest, TestSequenceMatcherRatioWithoutPenalty) {
// Two matching blocks, total matching blocks length is 4.
EXPECT_NEAR(SequenceMatcher(u"word", u"hello world", 0.0).Ratio(), 0.533,
0.001);
// One matching block, length is 4.
EXPECT_NEAR(SequenceMatcher(u"worl", u"hello world", 0.0).Ratio(), 0.533,
0.001);
// No matching block at all.
EXPECT_NEAR(SequenceMatcher(u"abcd", u"xyz", 0.0).Ratio(), 0.0, 0.001);
}
TEST_F(SequenceMatcherTest, TestSequenceMatcherRatioWithPenalty) {
// Two matching blocks, total matching blocks length is 4.
EXPECT_NEAR(SequenceMatcher(u"word", u"hello world", 0.1).Ratio(), 0.4825,
0.0001);
// One matching block, length is 4.
EXPECT_NEAR(SequenceMatcher(u"worl", u"hello world", 0.1).Ratio(), 0.533,
0.001);
// No matching block at all.
EXPECT_NEAR(SequenceMatcher(u"abcd", u"xyz", 0.1).Ratio(), 0.0, 0.001);
}
TEST_F(SequenceMatcherTest, TestSequenceMatcherRatioWithTextLengthAgnosticism) {
// Two matching blocks, total matching blocks length is 4.
EXPECT_NEAR(SequenceMatcher(u"word", u"hello world", 0.0)
.Ratio(/*text_length_agnostic=*/true),
0.615, 0.001);
// One matching block, length is 4.
EXPECT_NEAR(SequenceMatcher(u"worl", u"hello world", 0.0)
.Ratio(/*text_length_agnostic=*/true),
0.615, 0.001);
// No matching block at all.
EXPECT_NEAR(SequenceMatcher(u"abcd", u"xyz", 0.0).Ratio(), 0.0, 0.001);
}
TEST_F(SequenceMatcherTest, TestEmptyStrings) {
ASSERT_EQ(SequenceMatcher(u"", u"", 0.0).Ratio(), 0.0);
ASSERT_EQ(SequenceMatcher(u"", u"abcd", 0.0).Ratio(), 0.0);
}
} // namespace ash::string_matching