aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorregnat <rg@regnat.ovh>2022-03-03 13:12:27 +0100
committerregnat <rg@regnat.ovh>2022-03-07 10:09:10 +0100
commit2405bbbb5edd204d6031edcd470a2057f4a25782 (patch)
tree92f43382357a0a59ddba42400ef94bc4ce371112
parentc0792b1546ceed1c02a02ca1286ead55f79d5798 (diff)
Add some tests for the suggestions
-rw-r--r--src/libutil/suggestions.cc13
-rw-r--r--src/libutil/suggestions.hh2
-rw-r--r--src/libutil/tests/suggestions.cc43
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);
+ }
+}