diff options
author | regnat <rg@regnat.ovh> | 2022-03-03 13:12:27 +0100 |
---|---|---|
committer | regnat <rg@regnat.ovh> | 2022-03-07 10:09:10 +0100 |
commit | 2405bbbb5edd204d6031edcd470a2057f4a25782 (patch) | |
tree | 92f43382357a0a59ddba42400ef94bc4ce371112 | |
parent | c0792b1546ceed1c02a02ca1286ead55f79d5798 (diff) |
Add some tests for the suggestions
-rw-r--r-- | src/libutil/suggestions.cc | 13 | ||||
-rw-r--r-- | src/libutil/suggestions.hh | 2 | ||||
-rw-r--r-- | src/libutil/tests/suggestions.cc | 43 |
3 files changed, 48 insertions, 10 deletions
diff --git a/src/libutil/suggestions.cc b/src/libutil/suggestions.cc index 96b48416b..bcd93aa6b 100644 --- a/src/libutil/suggestions.cc +++ b/src/libutil/suggestions.cc @@ -5,15 +5,8 @@ namespace nix { -/** - * Return `some(distance)` where distance is an integer representing some - * notion of distance between both arguments. - * - * If the distance is too big, return none - */ -int distanceBetween(std::string_view first, std::string_view second) +int levenshteinDistance(std::string_view first, std::string_view second) { - // Levenshtein distance. // Implementation borrowed from // https://en.wikipedia.org/wiki/Levenshtein_distance#Iterative_with_two_matrix_rows @@ -49,7 +42,7 @@ Suggestions Suggestions::bestMatches ( std::set<Suggestion> res; for (const auto & possibleMatch : allMatches) { res.insert(Suggestion { - .distance = distanceBetween(query, possibleMatch), + .distance = levenshteinDistance(query, possibleMatch), .suggestion = possibleMatch, }); } @@ -63,7 +56,7 @@ Suggestions Suggestions::trim(int limit, int maxDistance) const int count = 0; for (auto & elt : suggestions) { - if (count >= limit || elt.distance >= maxDistance) + if (count >= limit || elt.distance > maxDistance) break; count++; res.insert(elt); diff --git a/src/libutil/suggestions.hh b/src/libutil/suggestions.hh index 3caed487a..76063a261 100644 --- a/src/libutil/suggestions.hh +++ b/src/libutil/suggestions.hh @@ -6,6 +6,8 @@ namespace nix { +int levenshteinDistance(std::string_view first, std::string_view second); + /** * A potential suggestion for the cli interface. */ diff --git a/src/libutil/tests/suggestions.cc b/src/libutil/tests/suggestions.cc new file mode 100644 index 000000000..279994abc --- /dev/null +++ b/src/libutil/tests/suggestions.cc @@ -0,0 +1,43 @@ +#include "suggestions.hh" +#include <gtest/gtest.h> + +namespace nix { + + struct LevenshteinDistanceParam { + std::string s1, s2; + int distance; + }; + + class LevenshteinDistanceTest : + public testing::TestWithParam<LevenshteinDistanceParam> { + }; + + TEST_P(LevenshteinDistanceTest, CorrectlyComputed) { + auto params = GetParam(); + + ASSERT_EQ(levenshteinDistance(params.s1, params.s2), params.distance); + ASSERT_EQ(levenshteinDistance(params.s2, params.s1), params.distance); + } + + INSTANTIATE_TEST_SUITE_P(LevenshteinDistance, LevenshteinDistanceTest, + testing::Values( + LevenshteinDistanceParam{"foo", "foo", 0}, + LevenshteinDistanceParam{"foo", "", 3}, + LevenshteinDistanceParam{"", "", 0}, + LevenshteinDistanceParam{"foo", "fo", 1}, + LevenshteinDistanceParam{"foo", "oo", 1}, + LevenshteinDistanceParam{"foo", "fao", 1}, + LevenshteinDistanceParam{"foo", "abc", 3} + ) + ); + + TEST(Suggestions, Trim) { + auto suggestions = Suggestions::bestMatches({"foooo", "bar", "fo", "gao"}, "foo"); + auto onlyOne = suggestions.trim(1); + ASSERT_EQ(onlyOne.suggestions.size(), 1); + ASSERT_TRUE(onlyOne.suggestions.begin()->suggestion == "fo"); + + auto closest = suggestions.trim(999, 2); + ASSERT_EQ(closest.suggestions.size(), 3); + } +} |